#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
VMboxy-PC Beta  2025-07-24
极客自制·图形版 QEMU 启动器
如要商用请保留本注释，违者必究
"""

import os
import sys
import platform
import subprocess
import threading
import time
import json
import logging
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
from pathlib import Path
import webbrowser
import re
import uuid
import io
import tkinter.dnd as tkdnd
from tkinter import Toplevel
import shutil
import zipfile

# ==================== 全局配置与初始化 ====================

# 设置系统编码兼容处理
if platform.system() == 'Windows':
    try:
        if hasattr(sys.stdout, 'reconfigure'):
            sys.stdout.reconfigure(encoding='utf-8')
        elif hasattr(sys.stdout, 'buffer'):
            import io
            sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    except (AttributeError, ValueError):
        # IDLE 环境不处理编码
        pass

# 创建配置目录
CONFIG_DIR = Path.home() / '.vmboxy'
CONFIG_DIR.mkdir(exist_ok=True)
VM_CONFIG_DIR = CONFIG_DIR / 'vm_configs'
VM_CONFIG_DIR.mkdir(exist_ok=True)
SHARED_DIR = CONFIG_DIR / 'shared'
SHARED_DIR.mkdir(exist_ok=True)
SETTINGS_FILE = CONFIG_DIR / 'settings.json'

# 日志配置
LOG_DIR = CONFIG_DIR / 'logs'
LOG_DIR.mkdir(exist_ok=True)
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(LOG_DIR / 'vmboxy.log', encoding='utf-8'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# QEMU默认路径配置
QEMU_DEFAULT_PATHS = {
    'Windows': [
        'C:/Program Files/qemu/qemu-system-x86_64.exe',
        'C:/Program Files/qemu/qemu-system-x86_64w.exe',
        'C:/Program Files/qemu/qemu-system-aarch64.exe',
        'C:/Program Files/qemu/qemu-system-aarch64w.exe',
        'C:/Program Files/qemu/qemu-system-arm.exe',
        'C:/Program Files/qemu/qemu-system-armw.exe',
        'C:/Program Files (x86)/qemu/qemu-system-x86_64.exe',
        'C:/Program Files (x86)/qemu/qemu-system-x86_64w.exe',
        'C:/Program Files (x86)/qemu/qemu-system-aarch64.exe',
        'C:/Program Files (x86)/qemu/qemu-system-aarch64w.exe',
        'C:/Program Files (x86)/qemu/qemu-system-arm.exe',
        'C:/Program Files (x86)/qemu/qemu-system-armw.exe'
    ],
    'Linux': [
        '/usr/bin/qemu-system-x86_64',
        '/usr/bin/qemu-system-aarch64',
        '/usr/bin/qemu-system-arm',
        '/usr/local/bin/qemu-system-x86_64',
        '/usr/local/bin/qemu-system-aarch64',
        '/usr/local/bin/qemu-system-arm',
        '/opt/qemu/bin/qemu-system-x86_64',
        '/opt/qemu/bin/qemu-system-aarch64',
        '/opt/qemu/bin/qemu-system-arm'
    ],
    'Darwin': [
        '/usr/local/bin/qemu-system-x86_64',
        '/usr/local/bin/qemu-system-aarch64',
        '/usr/local/bin/qemu-system-arm',
        '/opt/homebrew/bin/qemu-system-x86_64',
        '/opt/homebrew/bin/qemu-system-aarch64',
        '/opt/homebrew/bin/qemu-system-arm'
    ]
}

# 预设配置选项
PRESET_CONFIGS = {
    'architectures': {
        'x86_64': {
            'machines': [
                'pc-q35-8.2', 'pc-q35-8.1', 'pc-q35-8.0', 'pc-q35-7.2', 'pc-q35-7.1', 'pc-q35-7.0',
                'pc-q35-6.2', 'pc-q35-6.1', 'pc-q35-6.0', 'pc-q35-5.2', 'pc-q35-5.1', 'pc-q35-5.0',
                'pc-q35-4.2', 'pc-q35-4.1', 'pc-q35-4.0', 'pc-q35-3.1', 'pc-q35-3.0', 'q35',
                'pc-i440fx-8.2', 'pc-i440fx-8.1', 'pc-i440fx-8.0', 'pc-i440fx-7.2', 'pc-i440fx-7.1',
                'pc-i440fx-7.0', 'pc-i440fx-6.2', 'pc-i440fx-6.1', 'pc-i440fx-6.0', 'pc-i440fx-5.2',
                'pc-i440fx-5.1', 'pc-i440fx-5.0', 'pc-i440fx-4.2', 'pc-i440fx-4.1', 'pc-i440fx-4.0',
                'pc-i440fx-3.1', 'pc-i440fx-3.0', 'pc', 'microvm', 'isapc'
            ],
            'cpus': [
                'qemu64', 'phenom', 'core2duo', 'kvm64', 'coreduo', '486', 'pentium',
                'pentium2', 'pentium3', 'athlon', 'n270', 'Conroe', 'Penryn', 'Nehalem',
                'Nehalem-IBRS', 'Westmere', 'Westmere-IBRS', 'SandyBridge', 'SandyBridge-IBRS',
                'IvyBridge', 'IvyBridge-IBRS', 'Haswell', 'Haswell-noTSX', 'Haswell-IBRS',
                'Haswell-noTSX-IBRS', 'Broadwell', 'Broadwell-noTSX', 'Broadwell-IBRS',
                'Broadwell-noTSX-IBRS', 'Skylake-Client', 'Skylake-Client-IBRS',
                'Skylake-Client-noTSX-IBRS', 'Skylake-Server', 'Skylake-Server-IBRS',
                'Skylake-Server-noTSX-IBRS', 'Cascadelake-Server', 'Cascadelake-Server-noTSX',
                'Cooperlake', 'Icelake-Server', 'Icelake-Server-noTSX', 'Denverton',
                'Snowridge', 'KnightsMill', 'Opteron_G1', 'Opteron_G2', 'Opteron_G3',
                'Opteron_G4', 'Opteron_G5', 'EPYC', 'Dhyana', 'EPYC-Rome', 'EPYC-Milan',
                'EPYC-Genoa', 'SapphireRapids', 'GraniteRapids', 'ClearwaterForest',
                'SierraForest', 'YongFeng', 'base', 'max'
            ]
        },
        'arm64': {
            'machines': [
                'virt-8.2', 'virt-8.1', 'virt-8.0', 'virt-7.2', 'virt-7.1', 'virt-7.0',
                'virt-6.2', 'virt-6.1', 'virt-6.0', 'virt-5.2', 'virt-5.1', 'virt-5.0',
                'virt-4.2', 'virt-4.1', 'virt-4.0', 'virt-3.1', 'virt-3.0', 'virt',
                'raspi3b', 'raspi4b', 'imx6dl-sabrelite', 'imx6q-sabrelite',
                'imx6ul-sabrelite', 'imx6q-sabresd', 'imx6dl-sabresd', 'imx6ul-sabresd',
                'imx6ul-evk', 'imx6q-mx6qsabre', 'imx6dl-mx6sabresd', 'imx6q-mx6qsabresd'
            ],
            'cpus': [
                'cortex-a53', 'cortex-a57', 'cortex-a72', 'cortex-a73', 'cortex-a76',
                'cortex-a77', 'cortex-a78', 'cortex-a55', 'cortex-a510', 'cortex-a520',
                'cortex-a710', 'cortex-a715', 'cortex-x1', 'cortex-x2', 'cortex-x3',
                'neoverse-n1', 'neoverse-v1', 'neoverse-n2'
            ]
        },
        'arm32': {
            'machines': [
                'vexpress-a9', 'vexpress-a15', 'versatilepb', 'versatileab',
                'realview-pb-a8', 'realview-eb', 'realview-pbx-a9', 'integratorcp',
                'mainstone', 'akita', 'spitz', 'borzoi', 'terrier', 'tosa', 'z2'
            ],
            'cpus': [
                'arm1136', 'arm1176', 'arm926', 'arm946', 'arm1026', 'arm11mpcore',
                'arm1136-r2', 'arm1156', 'arm926-r2', 'arm1026', 'arm1176',
                'arm11mpcore', 'cortex-a8', 'cortex-a9', 'cortex-a7', 'cortex-a15'
            ]
        },
        'arm_m_profile': {
            'machines': [
                'mps2-an385', 'mps2-an386', 'mps2-an500', 'mps2-an505', 'mps2-an511',
                'mps2-an521', 'musca-a', 'musca-b1', 'musca-b', 'mps3-an547',
                'mps3-an524', 'mps3-an547', 'mps3-an547'
            ],
            'cpus': [
                'cortex-m0', 'cortex-m3', 'cortex-m4', 'cortex-m7', 'cortex-m23',
                'cortex-m33', 'cortex-m35p', 'cortex-m55', 'cortex-m85'
            ]
        },
        'arm_r_profile': {
            'machines': [
                'raspi2b', 'raspi1ap', 'raspi1b', 'raspi1b-plus', 'raspi0',
                'raspi0-w', 'raspi3ap', 'raspi3a', 'raspi4b-2gb', 'raspi4b-4gb',
                'raspi4b-8gb', 'raspi5', 'imx6ul-evk', 'imx6q-mx6qsabre',
                'imx6dl-mx6sabresd', 'imx6q-mx6qsabresd'
            ],
            'cpus': [
                'cortex-r5', 'cortex-r52', 'cortex-r7', 'cortex-r8'
            ]
        }
    },
    'memory_sizes': ['256M', '512M', '1G', '2G', '4G', '8G', '16G', '32G'],
    'vga_types': ['std', 'cirrus', 'vmware', 'qxl', 'virtio', 'ati', 'none'],
    'disk_interfaces': ['ide', 'scsi', 'virtio', 'nvme'],  # 新增硬盘接口类型
    'network_models': ['rtl8139', 'e1000', 'virtio-net-pci', 'ne2k_pci'],
    'disk_formats': ['qcow2', 'raw', 'vdi', 'vmdk'],
    'cache_modes': ['none', 'writethrough', 'writeback', 'directsync', 'unsafe'],
    'boot_orders': ['c', 'd', 'a', 'n', 'cd', 'dc', 'cda', 'dca'],
    'accel_types': ['kvm', 'tcg', 'whpx', 'hvf', 'none'],
    'themes': ['default', 'dark', 'light', 'blue', 'green', 'purple'],
    'log_levels': ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
}

# 翻译字典
TRANSLATIONS = {
    'en_US': {
        'app_title': "VMboxy-PC Beta",
        'file_menu': "File",
        'vm_menu': "VM",
        'help_menu': "Help",
        'vm_list': "Virtual Machines",
        'new_vm': "New",
        'delete_vm': "Delete",
        'rename_vm': "Rename",
        'start_vm': "Start VM",
        'stop_vm': "Stop VM",
        'save_config': "Save Config",
        'load_config': "Load Config",
        'basic_config': "Basic Config",
        'storage_config': "Storage Config",
        'network_config': "Network Config",
        'advanced_config': "Advanced Config",
        'shared_folder_config': "Shared Folder",
        'emulation_config': "Emulation Config",
        'about': "About",
        'log_console': "Log Console",
        'settings': "Settings",
        'vm_name': "VM Name:",
        'qemu_path': "QEMU Path:",
        'browse': "Browse",
        'detect': "Detect",
        'preview': "Preview",  # 新增
        'machine_type': "Machine Type:",
        'cpu_model': "CPU Model:",
        'memory_size': "Memory Size:",
        'vga_type': "VGA Type:",
        'enable_kvm': "Enable KVM",
        'enable_usb': "Enable USB",
        'accel_type': "Acceleration:",
        'no_hpet': "Disable HPET",
        'disk_config': "Disk Config",
        'disk_image': "Disk Image:",
        'disk_interface': "Disk Interface:",  # 新增
        'new_disk': "Create New Disk",
        'path': "Path:",
        'size': "Size:",
        'format': "Format:",
        'create_disk': "Create Disk",
        'cd_config': "CD/DVD Config",
        'iso_image': "ISO Image:",
        'fda_config': "Floppy Config",
        'fda_image': "Floppy Image:",
        'boot_config': "Boot Order",
        'boot_order': "Boot Order:",
        'boot_hint': "(c=disk, d=cdrom, a=floppy, n=network)",
        'network_device': "Network Device",
        'network_model': "Network Model:",
        'mac_address': "MAC Address:",
        'generate_mac': "Generate",
        'dns_server': "DNS Server:",
        'port_forward': "Port Forwarding",
        'host_port': "Host Port:",
        'guest_port': "Guest Port:",
        'add': "Add",
        'remove': "Remove",
        'bios_file': "BIOS File:",
        'snapshot': "Snapshot Management",
        'enable_snapshot': "Enable Snapshot Mode",
        'snapshot_name': "Snapshot Name:",
        'shared_folder': "Shared Folder",
        'enable_shared': "Enable Shared Folder",
        'shared_path': "Shared Path:",
        'shared_tag': "Shared Tag:",
        'other_options': "Other Options",
        'extra_params': "Extra Parameters:",
        'app_description': "VMBoxy-GUI is a graphical QEMU virtual machine launcher designed for users unfamiliar with the command line.",
        'developers': "Developed by:",
        'disclaimer': "Disclaimer: VMBoxy is independent of VMBox virtual machine and is a standalone PC application.",
        'repo': "Source Code:",
        'copyright': "© 2025 VMBoxy Development Team",
        'clear_log': "Clear Log",
        'save_log': "Save Log",
        'ready': "Ready",
        'language': "Language:",
        'theme': "Theme:",
        'log_level': "Log Level:",
        'auto_start': "Auto Start Last VM",
        'save_settings': "Save Settings",
        'reset_settings': "Reset Settings",
        'settings_saved': "Settings saved successfully",
        'vm_starting': "Starting VM...",
        'vm_running': "VM Running",
        'vm_stopped': "VM Stopped",
        'vm_failed': "Failed to start",
        'create_vm_title': "New Virtual Machine",
        'vm_name_empty': "VM name cannot be empty",
        'vm_exists': "VM name already exists",
        'delete_confirm': "Confirm Delete",
        'delete_prompt': "Are you sure you want to delete the VM '{}'?",
        'rename_title': "Rename Virtual Machine",
        'new_name': "New Name:",
        'name_exists': "VM name already exists",
        'select_qemu': "Select QEMU Executable",
        'select_disk': "Select Disk Image",
        'select_iso': "Select ISO Image",
        'select_fda': "Select Floppy Image",
        'create_disk_title': "Create New Disk",
        'disk_path_empty': "Please select disk save path",
        'disk_size_min': "Minimum disk size is 64MB",
        'disk_created': "Disk created successfully: {}",
        'disk_failed': "Failed to create disk",
        'invalid_size': "Invalid disk size format",
        'port_number': "Port number must be a number",
        'select_vm': "Please select a VM first",
        'qemu_missing': "Please select QEMU executable",
        'qemu_not_found': "QEMU executable not found",
        'no_boot_device': "Please specify at least one boot device",
        'config_saved': "Configuration saved",
        'config_load_failed': "Failed to load configuration: {}",
        'vm_created': "VM created: {}",
        'vm_deleted': "VM deleted: {}",
        'vm_renamed': "VM renamed from '{}' to '{}'",
        'vm_loaded': "VM configuration loaded: {}",
        'vm_imported': "VM imported: {}",
        'vm_exists_import': "VM '{}' already exists",
        'log_cleared': "Log cleared",
        'log_saved': "Log saved: {}",
        'qemu_selected': "QEMU path selected: {}",
        'disk_selected': "Disk loaded: {}",
        'iso_selected': "ISO loaded: {}",
        'fda_selected': "Floppy loaded: {}",
        'new_disk_path': "New disk path selected",
        'language_changed': "Language changed to {}",
        'theme_changed': "Theme changed to {}",
        'log_level_changed': "Log level changed to {}",
        'auto_start_changed': "Auto start setting changed to {}",
        'settings_reset': "Settings reset to defaults",
        'vm_not_found': "VM not found",
        'snapshot_mode': "Snapshot mode enabled",
        'mac_invalid': "Invalid MAC address format",
        'shared_folder_help': "Shared Folder Usage:\n1. Install virtiofs driver in VM\n2. Mount shared folder: mount -t virtiofs <tag> <mount point>\n3. Example: mount -t virtiofs shared /mnt/shared",
        'qemu_detected': "QEMU detected: {}",
        'no_vm_selected': "You have not selected any virtual machine",
        'preview_path': "Path: {}",  # 新增
        'default_vm_path': "Default VM Config Path:",
        'open_dir': "Open Folder",
        'backup_configs': "Backup All Configs",
        'restore_configs': "Restore Configs",
        'reset_qemu': "Reset QEMU Path",
        'check_updates': "Check for Updates",
        'open_log_dir': "Open Log Directory",
        'clear_cache': "Clear Cache",
        'backup_success': "Backup completed: {}",
        'restore_success': "Restore completed",
        'clear_cache_success': "Cache cleared",
    },
    'zh_CN': {
        'app_title': "VMboxy-PC Beta",
        'file_menu': "文件",
        'vm_menu': "虚拟机",
        'help_menu': "帮助",
        'vm_list': "虚拟机列表",
        'new_vm': "新建",
        'delete_vm': "删除",
        'rename_vm': "重命名",
        'start_vm': "启动虚拟机",
        'stop_vm': "停止虚拟机",
        'save_config': "保存配置",
        'load_config': "加载配置",
        'basic_config': "基本配置",
        'storage_config': "存储配置",
        'network_config': "网络配置",
        'advanced_config': "高级配置",
        'shared_folder_config': "共享文件夹",
        'emulation_config': "仿真配置",
        'about': "关于",
        'log_console': "日志控制台",
        'settings': "设置",
        'vm_name': "虚拟机名称:",
        'qemu_path': "QEMU路径:",
        'browse': "浏览",
        'detect': "检测",
        'preview': "预览",  # 新增
        'machine_type': "机器类型:",
        'cpu_model': "CPU型号:",
        'memory_size': "内存大小:",
        'vga_type': "显卡型号:",
        'enable_kvm': "启用KVM加速",
        'enable_usb': "启用USB设备",
        'accel_type': "加速模式:",
        'no_hpet': "禁用HPET",
        'disk_config': "硬盘配置",
        'disk_image': "硬盘镜像:",
        'disk_interface': "硬盘接口:",  # 新增
        'new_disk': "创建新磁盘",
        'path': "路径:",
        'size': "大小:",
        'format': "格式:",
        'create_disk': "创建磁盘",
        'cd_config': "光驱配置",
        'iso_image': "ISO镜像:",
        'fda_config': "软盘配置",
        'fda_image': "软盘镜像:",
        'boot_config': "启动顺序",
        'boot_order': "启动顺序:",
        'boot_hint': "(c=硬盘, d=光驱, a=软盘, n=网络)",
        'network_device': "网络设备",
        'network_model': "网卡型号:",
        'mac_address': "MAC地址:",
        'generate_mac': "生成",
        'dns_server': "DNS服务器:",
        'port_forward': "端口转发",
        'host_port': "主机端口:",
        'guest_port': "虚拟机端口:",
        'add': "添加",
        'remove': "删除",
        'bios_file': "BIOS文件:",
        'snapshot': "快照管理",
        'enable_snapshot': "启用快照模式",
        'snapshot_name': "快照名称:",
        'shared_folder': "共享文件夹",
        'enable_shared': "启用共享文件夹",
        'shared_path': "共享路径:",
        'shared_tag': "共享标签:",
        'other_options': "其他选项",
        'extra_params': "额外参数:",
        'app_description': "VMBoxy-GUI是一个图形化的QEMU虚拟机启动器，专为不熟悉命令行的用户设计。",
        'developers': "本程序由以下开发者共同制作:",
        'disclaimer': "声明：VMBoxy与VMBox虚拟机无关，是独立的PC端应用程序。",
        'repo': "开源地址:",
        'copyright': "© 2025 VMBoxy开发团队",
        'clear_log': "清空日志",
        'save_log': "保存日志",
        'ready': "就绪",
        'language': "语言:",
        'theme': "主题:",
        'log_level': "日志级别:",
        'auto_start': "自动启动上次虚拟机",
        'save_settings': "保存设置",
        'reset_settings': "重置设置",
        'settings_saved': "设置已保存",
        'vm_starting': "虚拟机启动中...",
        'vm_running': "虚拟机运行中",
        'vm_stopped': "虚拟机已停止",
        'vm_failed': "启动失败",
        'create_vm_title': "新建虚拟机",
        'vm_name_empty': "虚拟机名称不能为空",
        'vm_exists': "虚拟机名称已存在",
        'delete_confirm': "确认删除",
        'delete_prompt': "确定要删除虚拟机 '{}' 吗?",
        'rename_title': "重命名虚拟机",
        'new_name': "新名称:",
        'name_exists': "虚拟机名称已存在",
        'select_qemu': "选择QEMU可执行文件",
        'select_disk': "选择磁盘镜像",
        'select_iso': "选择ISO镜像",
        'select_fda': "选择软盘镜像",
        'create_disk_title': "创建新磁盘",
        'disk_path_empty': "请选择磁盘保存路径",
        'disk_size_min': "磁盘大小至少为64MB",
        'disk_created': "磁盘已创建: {}",
        'disk_failed': "磁盘创建失败",
        'invalid_size': "无效的磁盘大小格式",
        'port_number': "端口号必须是数字",
        'select_vm': "请先选择一个虚拟机",
        'qemu_missing': "请先选择QEMU可执行文件",
        'qemu_not_found': "QEMU可执行文件不存在",
        'no_boot_device': "请至少指定一个启动设备",
        'config_saved': "配置已保存",
        'config_load_failed': "加载配置失败: {}",
        'vm_created': "已创建虚拟机: {}",
        'vm_deleted': "已删除虚拟机: {}",
        'vm_renamed': "已将虚拟机 '{}' 重命名为 '{}'",
        'vm_loaded': "已加载虚拟机配置: {}",
        'vm_imported': "已导入虚拟机: {}",
        'vm_exists_import': "虚拟机 '{}' 已存在",
        'log_cleared': "日志已清空",
        'log_saved': "日志已保存: {}",
        'qemu_selected': "已选择QEMU路径: {}",
        'disk_selected': "已加载磁盘: {}",
        'iso_selected': "已加载ISO: {}",
        'fda_selected': "已加载软盘镜像: {}",
        'new_disk_path': "已选择新磁盘路径",
        'language_changed': "语言已切换为 {}",
        'theme_changed': "主题已切换为 {}",
        'log_level_changed': "日志级别已切换为 {}",
        'auto_start_changed': "自动启动设置已更改为 {}",
        'settings_reset': "设置已重置为默认值",
        'vm_not_found': "未找到虚拟机",
        'snapshot_mode': "已启用快照模式",
        'mac_invalid': "MAC地址格式无效",
        'shared_folder_help': "共享文件夹使用说明:\n1. 在虚拟机中安装 virtiofs 驱动\n2. 启动虚拟机后挂载共享文件夹: mount -t virtiofs <标签> <挂载点>\n3. 例如: mount -t virtiofs shared /mnt/shared",
        'qemu_detected': "已检测到QEMU路径: {}",
        'no_vm_selected': "您还没有选中任何虚拟机",
        'preview_path': "路径: {}",  # 新增
        'default_vm_path': "默认虚拟机配置路径:",
        'open_dir': "打开文件夹",
        'backup_configs': "备份所有配置",
        'restore_configs': "恢复配置",
        'reset_qemu': "重置QEMU路径",
        'check_updates': "检查更新",
        'open_log_dir': "打开日志目录",
        'clear_cache': "清空缓存",
        'backup_success': "备份完成: {}",
        'restore_success': "恢复完成",
        'clear_cache_success': "缓存已清空",
    }
}

# 当前语言
CURRENT_LANG = 'zh_CN'

def tr(key, *args):
    """翻译函数"""
    translation = TRANSLATIONS.get(CURRENT_LANG, {}).get(key, key)
    if args:
        try:
            return translation.format(*args)
        except:
            return translation
    return translation

# ==================== 工具函数 ====================

def find_qemu_executable():
    """自动查找QEMU可执行文件，支持x86_64、aarch64、arm、i386架构"""
    system = platform.system()
    paths = QEMU_DEFAULT_PATHS.get(system, [])
    
    # 按优先级顺序查找不同架构的QEMU
    for path in paths:
        if os.path.isfile(path):
            return path
    
    # 定义要查找的QEMU可执行文件名（按优先级排序）
    qemu_names = []
    if system == 'Windows':
        qemu_names = [
            'qemu-system-x86_64.exe',
            'qemu-system-x86_64w.exe',
            'qemu-system-aarch64.exe',
            'qemu-system-aarch64w.exe',
            'qemu-system-arm.exe',
            'qemu-system-armw.exe',
            'qemu-system-i386.exe',
            'qemu-system-i386w.exe'
        ]
    else:
        qemu_names = [
            'qemu-system-x86_64',
            'qemu-system-aarch64',
            'qemu-system-arm',
            'qemu-system-i386'
        ]
    
    # 在PATH环境变量中查找
    for qemu_name in qemu_names:
        try:
            if system == 'Windows':
                result = subprocess.run(['where', qemu_name], 
                                      capture_output=True, text=True, encoding='utf-8')
            else:
                result = subprocess.run(['which', qemu_name], 
                                      capture_output=True, text=True, encoding='utf-8')
                
            if result.returncode == 0:
                return result.stdout.strip()
        except:
            pass
    
    # 尝试查找所有QEMU可执行文件
    try:
        if system == 'Windows':
            result = subprocess.run(['where', 'qemu-system-*'], 
                                  capture_output=True, text=True, encoding='utf-8')
            if result.returncode == 0:
                for path in result.stdout.splitlines():
                    basename = os.path.basename(path.strip())
                    if any(name in basename for name in ['x86_64', 'aarch64', 'arm', 'i386']):
                        return path.strip()
        else:
            # 使用which命令查找所有qemu-system-*
            for name in qemu_names:
                try:
                    result = subprocess.run(['which', name], 
                                          capture_output=True, text=True, encoding='utf-8')
                    if result.returncode == 0:
                        return result.stdout.strip()
                except:
                    pass
    except:
        pass
    
    return ""

def run_command(cmd, cwd=None):
    """运行系统命令并返回结果"""
    try:
        logger.info(f"执行命令: {cmd}")
        # 使用列表形式避免shell注入
        if isinstance(cmd, str):
            cmd = shlex.split(cmd)
        result = subprocess.run(
            cmd, shell=False, capture_output=True, text=True, cwd=cwd, encoding='utf-8'
        )
        if result.returncode != 0:
            logger.error(f"命令失败: {result.stderr}")
        return result
    except Exception as e:
        logger.error(f"运行命令时出错: {e}")
        return None

def format_size(size_str):
    """格式化大小字符串"""
    size_str = size_str.upper()
    if size_str.endswith('M'):
        return int(size_str[:-1]) * 1024 * 1024
    elif size_str.endswith('G'):
        return int(size_str[:-1]) * 1024 * 1024 * 1024
    elif size_str.endswith('K'):
        return int(size_str[:-1]) * 1024
    else:
        return int(size_str)

def get_disk_info(image_path):
    """获取磁盘镜像信息"""
    cmd = f'qemu-img info "{image_path}"'
    result = run_command(cmd)
    if result and result.returncode == 0:
        return result.stdout
    return None

def create_disk_image(path, size, format_type='qcow2'):
    """创建磁盘镜像"""
    if not path or not size:
        return False
    
    # 验证路径安全
    try:
        path_obj = Path(path)
        path_obj.parent.mkdir(parents=True, exist_ok=True)
    except Exception:
        return False
    
    # 验证格式类型
    if format_type not in ['qcow2', 'raw', 'vmdk', 'vdi']:
        format_type = 'qcow2'
    
    cmd = ['qemu-img', 'create', '-f', format_type, str(path), str(size)]
    result = run_command(cmd)
    return result.returncode == 0 if result else False

def detect_accel_options(qemu_path):
    """检测QEMU支持的加速选项"""
    if not qemu_path or not os.path.exists(qemu_path):
        return PRESET_CONFIGS['accel_types']
    
    try:
        result = subprocess.run([qemu_path, '-accel', 'help'], capture_output=True, text=True, encoding='utf-8')
        if result.returncode == 0:
            # 解析支持的加速选项
            supported = []
            for line in result.stdout.splitlines():
                if line.startswith("Supported"):
                    continue
                for accel in line.split():
                    if accel and accel not in supported:
                        supported.append(accel)
            return supported if supported else PRESET_CONFIGS['accel_types']
    except:
        pass
    return PRESET_CONFIGS['accel_types']

def detect_cpu_features(qemu_path):
    """检测CPU特性"""
    features = {
        'kvm_available': False,
        'whpx_available': False,
        'hvf_available': False
    }
    
    if not qemu_path or not os.path.exists(qemu_path):
        return features
    
    # 检测KVM支持
    try:
        result = subprocess.run([qemu_path, '-enable-kvm', '?'], capture_output=True, text=True, encoding='utf-8')
        features['kvm_available'] = result.returncode == 0
    except:
        pass
    
    # 检测WHPX支持 (Windows Hypervisor Platform)
    try:
        result = subprocess.run([qemu_path, '-accel', 'whpx'], capture_output=True, text=True, encoding='utf-8')
        features['whpx_available'] = result.returncode == 0
    except:
        pass
    
    # 检测HVF支持 (Hypervisor.framework on macOS)
    try:
        result = subprocess.run([qemu_path, '-accel', 'hvf'], capture_output=True, text=True, encoding='utf-8')
        features['hvf_available'] = result.returncode == 0
    except:
        pass
    
    return features

def generate_mac_address():
    """生成随机的MAC地址"""
    mac = [0x52, 0x54, 0x00] + [0x00, 0x00, 0x00]
    for i in range(3, 6):
        mac[i] = uuid.uuid4().int & 0xFF
    return ':'.join(['{:02x}'.format(x) for x in mac])

def validate_mac_address(mac):
    """验证MAC地址格式"""
    pattern = r'^([0-9A-Fa-f]{2}:){5}([0-9A-Fa-f]{2})$'
    return re.match(pattern, mac) is not None

# 加载设置
def load_settings():
    """加载应用程序设置"""
    default_settings = {
        'language': 'zh_CN',
        'theme': 'default',
        'log_level': 'INFO',
        'auto_start_last_vm': False,
        'last_vm': ''
    }
    
    if SETTINGS_FILE.exists():
        try:
            with open(SETTINGS_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        except:
            logger.error("加载设置失败，使用默认设置")
    
    return default_settings

# 保存设置
def save_settings(settings):
    """保存应用程序设置"""
    try:
        with open(SETTINGS_FILE, 'w', encoding='utf-8') as f:
            json.dump(settings, f, indent=2, ensure_ascii=False)
        return True
    except Exception as e:
        logger.error(f"保存设置失败: {e}")
        return False

# ==================== 主应用窗口 ====================

class VMBoxyGUI(tk.Tk):
    """VMBoxy图形化启动器主窗口"""
    
    def __init__(self):
        super().__init__()
        
        # 加载设置
        self.settings = load_settings()
        global CURRENT_LANG
        CURRENT_LANG = self.settings.get('language', 'zh_CN')
        
        # 应用主题
        self.theme = self.settings.get('theme', 'default')
        
        # 窗口配置
        self.title(tr('app_title'))
        self.geometry("1200x800")
        self.apply_theme(self.theme)
        
        # 平台检测
        self.system = platform.system()
        
        # 配置变量
        self.qemu_path = tk.StringVar(value=find_qemu_executable())
        self.vm_name = tk.StringVar(value="MyVirtualMachine")
        self.architecture = tk.StringVar(value="x86_64")
        self.machine_type = tk.StringVar(value="q35")
        self.cpu_model = tk.StringVar(value="host")
        self.memory_size = tk.StringVar(value="2G")
        self.vga_type = tk.StringVar(value="vmware")
        self.bios_path = tk.StringVar()  # BIOS文件路径
        self.disk_path = tk.StringVar()
        self.disk_interface = tk.StringVar(value="ide")  # 新增硬盘接口类型
        self.iso_path = tk.StringVar()
        self.fda_path = tk.StringVar()  # 软盘路径
        self.network_model = tk.StringVar(value="virtio-net-pci")
        self.mac_address = tk.StringVar(value=generate_mac_address())
        self.dns_server = tk.StringVar(value="8.8.8.8")
        self.enable_usb = tk.BooleanVar(value=True)
        self.enable_kvm = tk.BooleanVar(value=True)
        self.accel_type = tk.StringVar(value="kvm")
        self.no_hpet = tk.BooleanVar(value=True)
        self.boot_order = tk.StringVar(value="cd")
        self.enable_snapshot = tk.BooleanVar(value=False)
        self.snapshot_name = tk.StringVar(value="snapshot1")
        self.extra_params = tk.StringVar()
        
        # 共享文件夹配置
        self.enable_shared_folder = tk.BooleanVar(value=False)
        self.shared_folder_path = tk.StringVar(value=str(SHARED_DIR))
        self.shared_folder_tag = tk.StringVar(value="shared")
        
        # 虚拟机列表
        self.vm_list = []
        self.current_vm = None
        
        # 端口转发列表
        self.port_forwards = []
        
        # 日志文本变量
        self.log_text = None
        
        # 检测QEMU支持的加速选项
        self.accel_options = detect_accel_options(self.qemu_path.get())
        self.cpu_features = detect_cpu_features(self.qemu_path.get())
        
        self.setup_ui()
        self.load_vm_list()
        self.update_accel_options()
        
        # 自动启动上次虚拟机
        if self.settings.get('auto_start_last_vm', False) and self.settings.get('last_vm'):
            self.auto_start_last_vm()
    
    def apply_theme(self, theme_name):
        """应用主题"""
        if theme_name == 'dark':
            self.bg_color = '#2c3e50'
            self.fg_color = '#ecf0f1'
            self.button_bg = '#3498db'
            self.button_fg = '#ffffff'
            self.list_bg = '#34495e'
            self.list_fg = '#ffffff'
            self.entry_bg = '#34495e'
            self.entry_fg = '#ffffff'
        elif theme_name == 'light':
            self.bg_color = '#f5f5f5'
            self.fg_color = '#333333'
            self.button_bg = '#4a90e2'
            self.button_fg = '#ffffff'
            self.list_bg = '#ffffff'
            self.list_fg = '#333333'
            self.entry_bg = '#ffffff'
            self.entry_fg = '#333333'
        elif theme_name == 'blue':
            self.bg_color = '#e3f2fd'
            self.fg_color = '#0d47a1'
            self.button_bg = '#2196f3'
            self.button_fg = '#ffffff'
            self.list_bg = '#bbdefb'
            self.list_fg = '#0d47a1'
            self.entry_bg = '#ffffff'
            self.entry_fg = '#0d47a1'
        elif theme_name == 'green':
            self.bg_color = '#e8f5e9'
            self.fg_color = '#1b5e20'
            self.button_bg = '#4caf50'
            self.button_fg = '#ffffff'
            self.list_bg = '#c8e6c9'
            self.list_fg = '#1b5e20'
            self.entry_bg = '#ffffff'
            self.entry_fg = '#1b5e20'
        elif theme_name == 'purple':
            self.bg_color = '#f3e5f5'
            self.fg_color = '#4a148c'
            self.button_bg = '#9c27b0'
            self.button_fg = '#ffffff'
            self.list_bg = '#e1bee7'
            self.list_fg = '#4a148c'
            self.entry_bg = '#ffffff'
            self.entry_fg = '#4a148c'
        else:  # default
            self.bg_color = '#ecf0f1'
            self.fg_color = '#2c3e50'
            self.button_bg = '#3498db'
            self.button_fg = '#ffffff'
            self.list_bg = '#ffffff'
            self.list_fg = '#2c3e50'
            self.entry_bg = '#ffffff'
            self.entry_fg = '#2c3e50'
        
        # 设置背景色
        self.configure(bg=self.bg_color)
    
    def update_accel_options(self):
        """根据系统环境更新加速选项"""
        # 根据检测到的特性更新默认值
        if self.system == 'Windows' and self.cpu_features['whpx_available']:
            self.accel_type.set('whpx')
        elif self.system == 'Darwin' and self.cpu_features['hvf_available']:
            self.accel_type.set('hvf')
        elif self.cpu_features['kvm_available']:
            self.accel_type.set('kvm')
        else:
            self.accel_type.set('tcg')
        
    def setup_ui(self):
        """设置用户界面"""
        # 主容器
        main_frame = tk.Frame(self, bg=self.bg_color)
        main_frame.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 顶部工具栏
        toolbar = tk.Frame(main_frame, bg=self.bg_color, height=50)
        toolbar.pack(fill='x', pady=(0, 10))
        
        tk.Label(
            toolbar, text=tr('app_title'), 
            font=('Arial', 16, 'bold'), fg=self.fg_color, bg=self.bg_color
        ).pack(side='left', padx=20)
        
        # 菜单按钮
        menu_frame = tk.Frame(toolbar, bg=self.bg_color)
        menu_frame.pack(side='right', padx=20)
        
        tk.Button(
            menu_frame, text=tr('file_menu'), command=self.show_file_menu,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        
        tk.Button(
            menu_frame, text=tr('vm_menu'), command=self.show_vm_menu,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        
        tk.Button(
            menu_frame, text=tr('help_menu'), command=self.show_help_menu,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        
        # 主布局
        main_container = tk.Frame(main_frame, bg=self.bg_color)
        main_container.pack(fill='both', expand=True)
        
        # 左侧虚拟机列表
        vm_list_frame = tk.LabelFrame(
            main_container, text=tr('vm_list'), bg=self.bg_color, 
            padx=10, pady=10, font=('Arial', 10, 'bold')
        )
        vm_list_frame.pack(side='left', fill='y', padx=(0, 10))
        
        self.vm_listbox = tk.Listbox(
            vm_list_frame, width=25, height=30, bg=self.list_bg, fg=self.list_fg, 
            relief='sunken', font=('Arial', 10)
        )
        self.vm_listbox.pack(fill='both', expand=True, pady=5)
        self.vm_listbox.bind('<<ListboxSelect>>', self.on_vm_selected)
        
        vm_button_frame = tk.Frame(vm_list_frame, bg=self.bg_color)
        vm_button_frame.pack(fill='x', pady=(5, 0))
        
        tk.Button(
            vm_button_frame, text=tr('new_vm'), command=self.create_vm,
            bg='#27ae60', fg='white', width=8
        ).pack(side='left', padx=2)
        
        tk.Button(
            vm_button_frame, text=tr('delete_vm'), command=self.delete_vm,
            bg='#e74c3c', fg='white', width=8
        ).pack(side='left', padx=2)
        
        tk.Button(
            vm_button_frame, text=tr('rename_vm'), command=self.rename_vm,
            bg=self.button_bg, fg=self.button_fg, width=8
        ).pack(side='left', padx=2)
        
        # 右侧配置区域
        config_frame = tk.Frame(main_container, bg=self.bg_color)
        config_frame.pack(side='right', fill='both', expand=True)
        
        # 创建Notebook
        self.notebook = ttk.Notebook(config_frame)
        self.notebook.pack(fill='both', expand=True)
        
        # 基本配置页面
        basic_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(basic_frame, text=tr('basic_config'))
        self.setup_basic_config(basic_frame)
        
        # 存储配置页面
        storage_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(storage_frame, text=tr('storage_config'))
        self.setup_storage_config(storage_frame)
        
        # 网络配置页面
        network_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(network_frame, text=tr('network_config'))
        self.setup_network_config(network_frame)
        
        # 仿真配置页面
        emulation_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(emulation_frame, text=tr('emulation_config'))
        self.setup_emulation_config(emulation_frame)
        
        # 高级配置页面
        advanced_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(advanced_frame, text=tr('advanced_config'))
        self.setup_advanced_config(advanced_frame)
        
        # 共享文件夹页面
        shared_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(shared_frame, text=tr('shared_folder_config'))
        self.setup_shared_folder_config(shared_frame)
        
        # 设置页面
        settings_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(settings_frame, text=tr('settings'))
        self.setup_settings_page(settings_frame)
        
        # 关于页面
        about_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(about_frame, text=tr('about'))
        self.setup_about_page(about_frame)
        
        # 日志页面
        log_frame = tk.Frame(self.notebook, bg=self.bg_color)
        self.notebook.add(log_frame, text=tr('log_console'))
        self.setup_log_console(log_frame)
        
        # 底部按钮
        button_frame = tk.Frame(main_frame, bg=self.bg_color)
        button_frame.pack(fill='x', pady=(10, 0))
        
        tk.Button(
            button_frame, text=tr('start_vm'), command=self.start_vm,
            bg='#27ae60', fg='white', font=('Arial', 12, 'bold'),
            width=15, height=2
        ).pack(side='left', padx=5)

        tk.Button(
            button_frame, text=tr('stop_vm'), command=self.stop_vm,
            bg='#e74c3c', fg='white', font=('Arial', 12, 'bold'),
            width=15, height=2
        ).pack(side='left', padx=5)

        tk.Button(
            button_frame, text=tr('save_config'), command=self.save_config,
            bg='#3498db', fg='white', font=('Arial', 12),
            width=15, height=2
        ).pack(side='left', padx=5)

        tk.Button(
            button_frame, text=tr('load_config'), command=self.load_config,
            bg='#f39c12', fg='white', font=('Arial', 12),
            width=15, height=2
        ).pack(side='left', padx=5)
        
        # 底部状态栏
        self.status_bar = tk.Label(
            main_frame, text=tr('ready'), bg='#bdc3c7', fg='black', 
            relief='sunken', anchor='w', font=('Arial', 9)
        )
        self.status_bar.pack(fill='x', pady=(10, 0))
    
    def setup_settings_page(self, parent):
        """设置设置页面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # ====== 通用设置 ======
        general_frame = tk.LabelFrame(
            frame, text="通用设置", bg=self.bg_color, font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        general_frame.pack(fill='x', pady=(0, 15))

        # 语言
        lang_frame = tk.Frame(general_frame, bg=self.bg_color)
        lang_frame.pack(fill='x', pady=5)
        tk.Label(lang_frame, text=tr('language'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.lang_var = tk.StringVar(value=self.settings.get('language', 'zh_CN'))
        lang_combo = ttk.Combobox(
            lang_frame, textvariable=self.lang_var,
            values=['zh_CN', 'en_US'], state='readonly', width=10
        )
        lang_combo.pack(side='left', padx=5)
        lang_combo.bind('<<ComboboxSelected>>', self.change_language)

        # 主题
        theme_frame = tk.Frame(general_frame, bg=self.bg_color)
        theme_frame.pack(fill='x', pady=5)
        tk.Label(theme_frame, text=tr('theme'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.theme_var = tk.StringVar(value=self.settings.get('theme', 'default'))
        theme_combo = ttk.Combobox(
            theme_frame, textvariable=self.theme_var,
            values=PRESET_CONFIGS['themes'], state='readonly', width=10
        )
        theme_combo.pack(side='left', padx=5)
        theme_combo.bind('<<ComboboxSelected>>', self.change_theme)

        # 日志级别
        log_frame = tk.Frame(general_frame, bg=self.bg_color)
        log_frame.pack(fill='x', pady=5)
        tk.Label(log_frame, text=tr('log_level'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.log_level_var = tk.StringVar(value=self.settings.get('log_level', 'INFO'))
        log_combo = ttk.Combobox(
            log_frame, textvariable=self.log_level_var,
            values=PRESET_CONFIGS['log_levels'], state='readonly', width=10
        )
        log_combo.pack(side='left', padx=5)
        log_combo.bind('<<ComboboxSelected>>', self.change_log_level)

        # 自动启动
        auto_frame = tk.Frame(general_frame, bg=self.bg_color)
        auto_frame.pack(fill='x', pady=5)
        self.auto_start_var = tk.BooleanVar(value=self.settings.get('auto_start_last_vm', False))
        tk.Checkbutton(
            auto_frame, text=tr('auto_start'), variable=self.auto_start_var,
            bg=self.bg_color, fg=self.fg_color, command=self.change_auto_start
        ).pack(side='left')

        # ====== 路径设置 ======
        path_frame = tk.LabelFrame(
            frame, text="路径设置", bg=self.bg_color, font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        path_frame.pack(fill='x', pady=(0, 15))

        # 默认配置文件路径
        default_path_frame = tk.Frame(path_frame, bg=self.bg_color)
        default_path_frame.pack(fill='x', pady=5)
        tk.Label(default_path_frame, text=tr('default_vm_path'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        tk.Label(
            default_path_frame, text=str(VM_CONFIG_DIR), bg=self.bg_color, fg='blue'
        ).pack(side='left')
        tk.Button(
            default_path_frame, text=tr('open_dir'), command=lambda: webbrowser.open(str(VM_CONFIG_DIR)),
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='right', padx=5)

        # ====== 工具按钮 ======
        tools_frame = tk.LabelFrame(
            frame, text="常用工具", bg=self.bg_color, font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        tools_frame.pack(fill='both', expand=True)

        # 备份配置
        backup_btn = tk.Button(
            tools_frame, text=tr('backup_configs'), command=self.backup_configs,
            bg='#3498db', fg='white', width=20
        )
        backup_btn.pack(pady=5)

        # 恢复配置
        restore_btn = tk.Button(
            tools_frame, text=tr('restore_configs'), command=self.restore_configs,
            bg='#f39c12', fg='white', width=20
        )
        restore_btn.pack(pady=5)

        # 重置QEMU路径
        reset_qemu_btn = tk.Button(
            tools_frame, text=tr('reset_qemu'), command=self.reset_qemu_path,
            bg='#e74c3c', fg='white', width=20
        )
        reset_qemu_btn.pack(pady=5)

        # 检查更新
        update_btn = tk.Button(
            tools_frame, text=tr('check_updates'), command=self.check_updates,
            bg='#27ae60', fg='white', width=20
        )
        update_btn.pack(pady=5)

        # 打开日志目录
        open_log_btn = tk.Button(
            tools_frame, text=tr('open_log_dir'), command=lambda: webbrowser.open(str(LOG_DIR)),
            bg='#9b59b6', fg='white', width=20
        )
        open_log_btn.pack(pady=5)

        # 清空缓存
        clear_cache_btn = tk.Button(
            tools_frame, text=tr('clear_cache'), command=self.clear_cache,
            bg='#95a5a6', fg='white', width=20
        )
        clear_cache_btn.pack(pady=5)

        # ====== 底部按钮 ======
        bottom_frame = tk.Frame(frame, bg=self.bg_color)
        bottom_frame.pack(fill='x', pady=20)

        tk.Button(
            bottom_frame, text=tr('save_settings'), command=self.save_settings,
            bg=self.button_bg, fg=self.button_fg, width=15
        ).pack(side='left', padx=10)

        tk.Button(
            bottom_frame, text=tr('reset_settings'), command=self.reset_settings,
            bg='#e74c3c', fg='white', width=15
        ).pack(side='left', padx=10)
    
    def setup_basic_config(self, parent):
        """设置基本配置界面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建带标题的框架
        config_frame = tk.LabelFrame(
            frame, text=tr('basic_config'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        config_frame.pack(fill='both', expand=True)
        
        # 虚拟机名称
        name_frame = tk.Frame(config_frame, bg=self.bg_color)
        name_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(name_frame, text=tr('vm_name'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        name_entry = tk.Entry(name_frame, textvariable=self.vm_name, width=40, 
                            bg=self.entry_bg, fg=self.entry_fg)
        name_entry.pack(side='left', padx=5)
        
        # QEMU路径
        path_frame = tk.Frame(config_frame, bg=self.bg_color)
        path_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(path_frame, text=tr('qemu_path'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        path_entry = tk.Entry(path_frame, textvariable=self.qemu_path, width=60,
                            bg=self.entry_bg, fg=self.entry_fg)
        path_entry.pack(side='left', padx=5)
        
        tk.Button(
            path_frame, text=tr('browse'), command=self.browse_qemu_path,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        tk.Button(
            path_frame, text=tr('detect'), command=self.detect_qemu,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        tk.Button(
            path_frame, text=tr('preview'), command=lambda: self.show_path_preview(self.qemu_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).pack(side='left', padx=5)
        
        # 架构选择
        arch_frame = tk.Frame(config_frame, bg=self.bg_color)
        arch_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(arch_frame, text="架构:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        arch_combo = ttk.Combobox(
            arch_frame, textvariable=self.architecture,
            values=list(PRESET_CONFIGS['architectures'].keys()), state='readonly', width=15
        )
        arch_combo.pack(side='left', padx=5)
        
        # 机器类型
        machine_frame = tk.Frame(config_frame, bg=self.bg_color)
        machine_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(machine_frame, text=tr('machine_type'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        machine_combo = ttk.Combobox(
            machine_frame, textvariable=self.machine_type,
            values=[], state='readonly', width=25
        )
        machine_combo.pack(side='left', padx=5)
        
        # CPU配置
        cpu_frame = tk.Frame(config_frame, bg=self.bg_color)
        cpu_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(cpu_frame, text=tr('cpu_model'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_combo = ttk.Combobox(
            cpu_frame, textvariable=self.cpu_model,
            values=[], state='readonly', width=25
        )
        self.cpu_combo.pack(side='left', padx=5)
        
        # 动态更新机器和CPU列表
        def update_machine_list(event=None):
            arch = self.architecture.get()
            if arch in PRESET_CONFIGS['architectures']:
                machines = PRESET_CONFIGS['architectures'][arch]['machines']
                machine_combo['values'] = machines
                if machines:
                    self.machine_type.set(machines[0])
                update_cpu_list()
        
        def update_cpu_list(event=None):
            arch = self.architecture.get()
            if arch in PRESET_CONFIGS['architectures']:
                cpus = PRESET_CONFIGS['architectures'][arch]['cpus']
                self.cpu_combo['values'] = cpus
                if cpus:
                    self.cpu_model.set(cpus[0])
        
        arch_combo.bind('<<ComboboxSelected>>', update_machine_list)
        machine_combo.bind('<<ComboboxSelected>>', update_cpu_list)
        
        # 初始化
        update_machine_list()
        
        # 内存配置
        mem_frame = tk.Frame(config_frame, bg=self.bg_color)
        mem_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(mem_frame, text=tr('memory_size'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        mem_combo = ttk.Combobox(
            mem_frame, textvariable=self.memory_size,
            values=PRESET_CONFIGS['memory_sizes'], state='readonly', width=10
        )
        mem_combo.pack(side='left', padx=5)
        
        # 显卡配置
        vga_frame = tk.Frame(config_frame, bg=self.bg_color)
        vga_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(vga_frame, text=tr('vga_type'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        vga_combo = ttk.Combobox(
            vga_frame, textvariable=self.vga_type,
            values=PRESET_CONFIGS['vga_types'], state='readonly', width=15
        )
        vga_combo.pack(side='left', padx=5)
        
        # BIOS文件配置
        bios_frame = tk.Frame(config_frame, bg=self.bg_color)
        bios_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(bios_frame, text=tr('bios_file'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        bios_entry = tk.Entry(bios_frame, textvariable=self.bios_path, width=60,
                            bg=self.entry_bg, fg=self.entry_fg)
        bios_entry.pack(side='left', padx=5)
        
        tk.Button(
            bios_frame, text=tr('browse'), command=self.browse_bios_file,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        tk.Button(
            bios_frame, text=tr('preview'), command=lambda: self.show_path_preview(self.bios_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).pack(side='left', padx=5)
        
        # 加速选项
        accel_frame = tk.Frame(config_frame, bg=self.bg_color)
        accel_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(accel_frame, text=tr('accel_type'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        accel_combo = ttk.Combobox(
            accel_frame, textvariable=self.accel_type,
            values=self.accel_options, state='readonly', width=10
        )
        accel_combo.pack(side='left', padx=5)
        
        # 其他选项
        other_frame = tk.Frame(config_frame, bg=self.bg_color)
        other_frame.pack(fill='x', pady=(0, 10))
        
        # 删除重复的KVM加速复选框
        # 只保留USB和HPET选项
        
        tk.Checkbutton(
            other_frame, text=tr('enable_usb'), variable=self.enable_usb,
            bg=self.bg_color, fg=self.fg_color
        ).pack(side='left', padx=5)
        
        tk.Checkbutton(
            other_frame, text=tr('no_hpet'), variable=self.no_hpet,
            bg=self.bg_color, fg=self.fg_color
        ).pack(side='left', padx=5)
    
    def setup_storage_config(self, parent):
        """设置存储配置界面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 磁盘配置
        disk_group = tk.LabelFrame(
            frame, text=tr('disk_config'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        disk_group.pack(fill='x', pady=(0, 10))
        
        # 现有磁盘
        tk.Label(disk_group, text=tr('disk_image'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=0, sticky='w')
        disk_entry = tk.Entry(disk_group, textvariable=self.disk_path, width=60,
                            bg=self.entry_bg, fg=self.entry_fg)
        disk_entry.grid(row=0, column=1, padx=5, pady=5)
        
        # 添加硬盘接口类型选择
        tk.Label(disk_group, text=tr('disk_interface'), bg=self.bg_color, fg=self.fg_color).grid(row=1, column=0, sticky='w')
        interface_combo = ttk.Combobox(
            disk_group, textvariable=self.disk_interface,
            values=PRESET_CONFIGS['disk_interfaces'], state='readonly', width=10
        )
        interface_combo.grid(row=1, column=1, sticky='w', padx=5)
        
        tk.Button(
            disk_group, text=tr('browse'), command=self.browse_disk,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).grid(row=0, column=2, padx=5)
        tk.Button(
            disk_group, text=tr('preview'), command=lambda: self.show_path_preview(self.disk_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).grid(row=0, column=3, padx=5)
        
        # 创建新磁盘
        create_group = tk.LabelFrame(
            disk_group, text=tr('new_disk'), bg=self.bg_color, 
            font=('Arial', 9), padx=10, pady=10
        )
        create_group.grid(row=2, column=0, columnspan=4, pady=10, sticky='ew')
        
        self.new_disk_path = tk.StringVar()
        self.new_disk_size = tk.StringVar(value="10G")
        self.new_disk_format = tk.StringVar(value="qcow2")
        
        tk.Label(create_group, text=tr('path'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=0, sticky='w')
        new_path_entry = tk.Entry(create_group, textvariable=self.new_disk_path, width=40,
                bg=self.entry_bg, fg=self.entry_fg)
        new_path_entry.grid(row=0, column=1, padx=5)
        
        tk.Button(
            create_group, text=tr('browse'), command=self.choose_new_disk_path,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).grid(row=0, column=2, padx=5)
        tk.Button(
            create_group, text=tr('preview'), command=lambda: self.show_path_preview(self.new_disk_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).grid(row=0, column=3, padx=5)
        
        tk.Label(create_group, text=tr('size'), bg=self.bg_color, fg=self.fg_color).grid(row=1, column=0, sticky='w')
        tk.Entry(create_group, textvariable=self.new_disk_size, width=10,
                bg=self.entry_bg, fg=self.entry_fg).grid(row=1, column=1, sticky='w', padx=5)
        
        tk.Label(create_group, text=tr('format'), bg=self.bg_color, fg=self.fg_color).grid(row=2, column=0, sticky='w')
        format_combo = ttk.Combobox(
            create_group, textvariable=self.new_disk_format,
            values=PRESET_CONFIGS['disk_formats'], state='readonly', width=10
        )
        format_combo.grid(row=2, column=1, sticky='w', padx=5)
        
        tk.Button(
            create_group, text=tr('create_disk'), command=self.create_disk,
            bg='#27ae60', fg='white', relief='flat'
        ).grid(row=3, column=0, columnspan=4, pady=10)
        
        # 光驱配置
        cd_group = tk.LabelFrame(
            frame, text=tr('cd_config'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        cd_group.pack(fill='x', pady=(0, 10))
        
        tk.Label(cd_group, text=tr('iso_image'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=0, sticky='w')
        cd_entry = tk.Entry(cd_group, textvariable=self.iso_path, width=60,
                           bg=self.entry_bg, fg=self.entry_fg)
        cd_entry.grid(row=0, column=1, padx=5, pady=5)
        
        tk.Button(
            cd_group, text=tr('browse'), command=self.browse_iso,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).grid(row=0, column=2, padx=5)
        tk.Button(
            cd_group, text=tr('preview'), command=lambda: self.show_path_preview(self.iso_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).grid(row=0, column=3, padx=5)
        
        # 软盘配置
        fda_group = tk.LabelFrame(
            frame, text=tr('fda_config'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        fda_group.pack(fill='x', pady=(0, 10))
        
        tk.Label(fda_group, text=tr('fda_image'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=0, sticky='w')
        fda_entry = tk.Entry(fda_group, textvariable=self.fda_path, width=60,
                            bg=self.entry_bg, fg=self.entry_fg)
        fda_entry.grid(row=0, column=1, padx=5, pady=5)
        
        tk.Button(
            fda_group, text=tr('browse'), command=self.browse_fda,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).grid(row=0, column=2, padx=5)
        tk.Button(
            fda_group, text=tr('preview'), command=lambda: self.show_path_preview(self.fda_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).grid(row=0, column=3, padx=5)
        
        # 启动顺序
        boot_group = tk.LabelFrame(
            frame, text=tr('boot_config'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        boot_group.pack(fill='x', pady=(0, 10))
        
        tk.Label(boot_group, text=tr('boot_order'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=0, sticky='w')
        boot_combo = ttk.Combobox(
            boot_group, textvariable=self.boot_order,
            values=PRESET_CONFIGS['boot_orders'], state='readonly', width=10
        )
        boot_combo.grid(row=0, column=1, sticky='w', padx=5)
        tk.Label(boot_group, text=tr('boot_hint'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=2, sticky='w')
    
    def setup_network_config(self, parent):
        """设置网络配置界面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 网络设备配置
        device_group = tk.LabelFrame(
            frame, text=tr('network_device'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        device_group.pack(fill='x', pady=(0, 10))
        
        tk.Label(device_group, text=tr('network_model'), bg=self.bg_color, fg=self.fg_color).grid(row=0, column=0, sticky='w')
        net_combo = ttk.Combobox(
            device_group, textvariable=self.network_model,
            values=PRESET_CONFIGS['network_models'], state='readonly', width=20
        )
        net_combo.grid(row=0, column=1, padx=5, pady=5)
        
        tk.Label(device_group, text=tr('mac_address'), bg=self.bg_color, fg=self.fg_color).grid(row=1, column=0, sticky='w')
        mac_frame = tk.Frame(device_group, bg=self.bg_color)
        mac_frame.grid(row=1, column=1, padx=5, sticky='w')
        mac_entry = tk.Entry(mac_frame, textvariable=self.mac_address, width=20, 
                           bg=self.entry_bg, fg=self.entry_fg)
        mac_entry.pack(side='left')
        tk.Button(
            mac_frame, text=tr('generate_mac'), command=self.generate_mac,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        
        tk.Label(device_group, text=tr('dns_server'), bg=self.bg_color, fg=self.fg_color).grid(row=2, column=0, sticky='w')
        tk.Entry(device_group, textvariable=self.dns_server, width=20,
               bg=self.entry_bg, fg=self.entry_fg).grid(row=2, column=1, padx=5)
        
        # 端口转发配置
        forward_group = tk.LabelFrame(
            frame, text=tr('port_forward'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        forward_group.pack(fill='x', pady=(0, 10))
        
        self.port_forwards = []
        self.forward_listbox = tk.Listbox(forward_group, height=5, width=50,
                                         bg=self.list_bg, fg=self.list_fg)
        self.forward_listbox.pack(pady=5)
        
        forward_frame = tk.Frame(forward_group, bg=self.bg_color)
        forward_frame.pack(fill='x')
        
        self.host_port = tk.StringVar()
        self.guest_port = tk.StringVar()
        
        tk.Label(forward_frame, text=tr('host_port'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        tk.Entry(forward_frame, textvariable=self.host_port, width=10,
                bg=self.entry_bg, fg=self.entry_fg).pack(side='left', padx=5)
        tk.Label(forward_frame, text=tr('guest_port'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        tk.Entry(forward_frame, textvariable=self.guest_port, width=10,
                bg=self.entry_bg, fg=self.entry_fg).pack(side='left', padx=5)
        tk.Button(
            forward_frame, text=tr('add'), command=self.add_port_forward,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        tk.Button(
            forward_frame, text=tr('remove'), command=self.remove_port_forward,
            bg='#e74c3c', fg='white', relief='flat'
        ).pack(side='left', padx=5)
    
    def setup_emulation_config(self, parent):
        """设置仿真配置界面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 创建滚动区域
        canvas = tk.Canvas(frame, bg=self.bg_color, highlightthickness=0)
        scrollbar = ttk.Scrollbar(frame, orient="vertical", command=canvas.yview)
        scrollable_frame = tk.Frame(canvas, bg=self.bg_color)
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        # 添加鼠标滚轮支持
        def _on_mousewheel(event):
            canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        
        canvas.bind_all("<MouseWheel>", _on_mousewheel)
        
        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")
        
        # CPU高级配置
        cpu_advanced_group = tk.LabelFrame(
            scrollable_frame, text="CPU高级配置", bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        cpu_advanced_group.pack(fill='x', pady=(0, 10))
        
        # CPU Family
        family_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        family_frame.pack(fill='x', pady=(0, 5))
        tk.Label(family_frame, text="CPU Family:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_family = tk.StringVar()
        family_entry = tk.Entry(family_frame, textvariable=self.cpu_family, width=10,
                              bg=self.entry_bg, fg=self.entry_fg)
        family_entry.pack(side='left', padx=5)
        tk.Label(family_frame, text="(例如: 6)", bg=self.bg_color, fg='gray').pack(side='left')
        
        # CPU Model
        model_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        model_frame.pack(fill='x', pady=(0, 5))
        tk.Label(model_frame, text="CPU Model:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_model_num = tk.StringVar()
        model_entry = tk.Entry(model_frame, textvariable=self.cpu_model_num, width=10,
                             bg=self.entry_bg, fg=self.entry_fg)
        model_entry.pack(side='left', padx=5)
        tk.Label(model_frame, text="(例如: 151 - 记得将16进制转为10进制)", bg=self.bg_color, fg='gray').pack(side='left')
        
        # CPU Stepping
        stepping_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        stepping_frame.pack(fill='x', pady=(0, 5))
        tk.Label(stepping_frame, text="CPU Stepping:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_stepping = tk.StringVar()
        stepping_entry = tk.Entry(stepping_frame, textvariable=self.cpu_stepping, width=10,
                                bg=self.entry_bg, fg=self.entry_fg)
        stepping_entry.pack(side='left', padx=5)
        tk.Label(stepping_frame, text="(例如: 2)", bg=self.bg_color, fg='gray').pack(side='left')
        
        # CPU Vendor
        vendor_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        vendor_frame.pack(fill='x', pady=(0, 5))
        tk.Label(vendor_frame, text="CPU Vendor:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_vendor = tk.StringVar()
        vendor_entry = tk.Entry(vendor_frame, textvariable=self.cpu_vendor, width=15,
                            bg=self.entry_bg, fg=self.entry_fg)
        vendor_entry.pack(side='left', padx=5)
        tk.Label(vendor_frame, text="(例如: GenuineIntel)", bg=self.bg_color, fg='gray').pack(side='left')
        
        # CPU Level
        level_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        level_frame.pack(fill='x', pady=(0, 5))
        tk.Label(level_frame, text="CPU Level:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_level = tk.StringVar()
        level_entry = tk.Entry(level_frame, textvariable=self.cpu_level, width=10,
                             bg=self.entry_bg, fg=self.entry_fg)
        level_entry.pack(side='left', padx=5)
        tk.Label(level_frame, text="(例如: 22)", bg=self.bg_color, fg='gray').pack(side='left')
        
        # CPU XLevel
        xlevel_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        xlevel_frame.pack(fill='x', pady=(0, 5))
        tk.Label(xlevel_frame, text="CPU XLevel:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_xlevel = tk.StringVar()
        xlevel_entry = tk.Entry(xlevel_frame, textvariable=self.cpu_xlevel, width=10,
                              bg=self.entry_bg, fg=self.entry_fg)
        xlevel_entry.pack(side='left', padx=5)
        tk.Label(xlevel_frame, text="(例如: 2147483647)", bg=self.bg_color, fg='gray').pack(side='left')
        
        # CPU UUID
        uuid_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        uuid_frame.pack(fill='x', pady=(0, 5))
        tk.Label(uuid_frame, text="CPU UUID:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_uuid = tk.StringVar()
        uuid_entry = tk.Entry(uuid_frame, textvariable=self.cpu_uuid, width=40,
                           bg=self.entry_bg, fg=self.entry_fg)
        uuid_entry.pack(side='left', padx=5)

        # CPU Model ID (显示名称)
        model_id_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        model_id_frame.pack(fill='x', pady=(0, 5))
        tk.Label(model_id_frame, text="CPU显示名称:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_model_id = tk.StringVar()
        model_id_entry = tk.Entry(model_id_frame, textvariable=self.cpu_model_id, width=40,
                           bg=self.entry_bg, fg=self.entry_fg)
        model_id_entry.pack(side='left', padx=5)
        tk.Label(model_id_frame, text="(例如: 12th Gen Intel(R) Core(TM) i9-12900KS @ 5.50GHz)", bg=self.bg_color, fg='gray').pack(side='left')

        # L3缓存
        l3cache_frame = tk.Frame(cpu_advanced_group, bg=self.bg_color)
        l3cache_frame.pack(fill='x', pady=(0, 5))
        self.cpu_l3cache = tk.BooleanVar()
        l3cache_check = tk.Checkbutton(
            l3cache_frame, text="启用L3缓存", variable=self.cpu_l3cache,
            bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color
        )
        l3cache_check.pack(side='left')
        
        # 硬件模拟配置
        hardware_group = tk.LabelFrame(
            scrollable_frame, text="硬件模拟配置", bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        hardware_group.pack(fill='x', pady=(0, 10))
        
        # 主板型号
        board_frame = tk.Frame(hardware_group, bg=self.bg_color)
        board_frame.pack(fill='x', pady=(0, 5))
        tk.Label(board_frame, text="主板型号:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.motherboard_model = tk.StringVar()
        board_entry = tk.Entry(board_frame, textvariable=self.motherboard_model, width=30,
                             bg=self.entry_bg, fg=self.entry_fg)
        board_entry.pack(side='left', padx=5)
        
        # 芯片组型号
        chipset_frame = tk.Frame(hardware_group, bg=self.bg_color)
        chipset_frame.pack(fill='x', pady=(0, 5))
        tk.Label(chipset_frame, text="芯片组型号:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.chipset_model = tk.StringVar()
        chipset_entry = tk.Entry(chipset_frame, textvariable=self.chipset_model, width=30,
                               bg=self.entry_bg, fg=self.entry_fg)
        chipset_entry.pack(side='left', padx=5)
        
        # 内存型号
        memory_frame = tk.Frame(hardware_group, bg=self.bg_color)
        memory_frame.pack(fill='x', pady=(0, 5))
        tk.Label(memory_frame, text="内存型号:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.memory_model = tk.StringVar()
        memory_entry = tk.Entry(memory_frame, textvariable=self.memory_model, width=30,
                              bg=self.entry_bg, fg=self.entry_fg)
        memory_entry.pack(side='left', padx=5)
        
        # 硬盘型号
        disk_model_frame = tk.Frame(hardware_group, bg=self.bg_color)
        disk_model_frame.pack(fill='x', pady=(0, 5))
        tk.Label(disk_model_frame, text="硬盘型号:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.disk_model = tk.StringVar()
        disk_model_entry = tk.Entry(disk_model_frame, textvariable=self.disk_model, width=30,
                                  bg=self.entry_bg, fg=self.entry_fg)
        disk_model_entry.pack(side='left', padx=5)
        
        # CPU拓扑配置
        topology_group = tk.LabelFrame(
            scrollable_frame, text="CPU拓扑配置", bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        topology_group.pack(fill='x', pady=(0, 10))
        
        # 插槽数
        sockets_frame = tk.Frame(topology_group, bg=self.bg_color)
        sockets_frame.pack(fill='x', pady=(0, 5))
        tk.Label(sockets_frame, text="插槽数:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_sockets = tk.StringVar(value="1")
        sockets_entry = tk.Entry(sockets_frame, textvariable=self.cpu_sockets, width=10,
                               bg=self.entry_bg, fg=self.entry_fg)
        sockets_entry.pack(side='left', padx=5)
        
        # 每插槽核心数
        cores_frame = tk.Frame(topology_group, bg=self.bg_color)
        cores_frame.pack(fill='x', pady=(0, 5))
        tk.Label(cores_frame, text="每插槽核心数:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_cores = tk.StringVar(value="2")
        cores_entry = tk.Entry(cores_frame, textvariable=self.cpu_cores, width=10,
                             bg=self.entry_bg, fg=self.entry_fg)
        cores_entry.pack(side='left', padx=5)
        
        # 每核心线程数
        threads_frame = tk.Frame(topology_group, bg=self.bg_color)
        threads_frame.pack(fill='x', pady=(0, 5))
        tk.Label(threads_frame, text="每核心线程数:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.cpu_threads = tk.StringVar(value="1")
        threads_entry = tk.Entry(threads_frame, textvariable=self.cpu_threads, width=10,
                               bg=self.entry_bg, fg=self.entry_fg)
        threads_entry.pack(side='left', padx=5)
        
        # 性能优化
        performance_group = tk.LabelFrame(
            scrollable_frame, text="性能优化", bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        performance_group.pack(fill='x', pady=(0, 10))
        
        # TCG线程模式
        tcg_frame = tk.Frame(performance_group, bg=self.bg_color)
        tcg_frame.pack(fill='x', pady=(0, 5))
        tk.Label(tcg_frame, text="TCG线程模式:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.tcg_thread = tk.StringVar(value="multi")
        tcg_combo = ttk.Combobox(
            tcg_frame, textvariable=self.tcg_thread,
            values=["single", "multi"], state='readonly', width=10
        )
        tcg_combo.pack(side='left', padx=5)
        
        # 转换块缓存大小
        tbsize_frame = tk.Frame(performance_group, bg=self.bg_color)
        tbsize_frame.pack(fill='x', pady=(0, 5))
        tk.Label(tbsize_frame, text="转换块缓存大小:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.tcg_tb_size = tk.StringVar(value="8192")
        tbsize_entry = tk.Entry(tbsize_frame, textvariable=self.tcg_tb_size, width=10,
                              bg=self.entry_bg, fg=self.entry_fg)
        tbsize_entry.pack(side='left', padx=5)
        tk.Label(tbsize_frame, text="KB", bg=self.bg_color, fg='gray').pack(side='left')
        
        # SMBIOS配置
        smbios_group = tk.LabelFrame(
            scrollable_frame, text="SMBIOS配置", bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        smbios_group.pack(fill='x', pady=(0, 10))

        # BIOS信息
        bios_frame = tk.Frame(smbios_group, bg=self.bg_color)
        bios_frame.pack(fill='x', pady=(0, 5))
        tk.Label(bios_frame, text="BIOS厂商:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.bios_vendor = tk.StringVar()
        bios_vendor_entry = tk.Entry(bios_frame, textvariable=self.bios_vendor, width=20,
                                   bg=self.entry_bg, fg=self.entry_fg)
        bios_vendor_entry.pack(side='left', padx=5)
        tk.Label(bios_frame, text="(例如: American Megatrends Inc.)", bg=self.bg_color, fg='gray').pack(side='left')

        bios_version_frame = tk.Frame(smbios_group, bg=self.bg_color)
        bios_version_frame.pack(fill='x', pady=(0, 5))
        tk.Label(bios_version_frame, text="BIOS版本:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.bios_version = tk.StringVar()
        bios_version_entry = tk.Entry(bios_version_frame, textvariable=self.bios_version, width=20,
                                   bg=self.entry_bg, fg=self.entry_fg)
        bios_version_entry.pack(side='left', padx=5)
        tk.Label(bios_version_frame, text="(例如: 5.12)", bg=self.bg_color, fg='gray').pack(side='left')

        bios_date_frame = tk.Frame(smbios_group, bg=self.bg_color)
        bios_date_frame.pack(fill='x', pady=(0, 5))
        tk.Label(bios_date_frame, text="BIOS发布日期:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.bios_release_date = tk.StringVar()
        bios_date_entry = tk.Entry(bios_date_frame, textvariable=self.bios_release_date, width=20,
                                 bg=self.entry_bg, fg=self.entry_fg)
        bios_date_entry.pack(side='left', padx=5)
        tk.Label(bios_date_frame, text="(例如: 01/01/2024)", bg=self.bg_color, fg='gray').pack(side='left')

        # 系统信息
        system_frame = tk.Frame(smbios_group, bg=self.bg_color)
        system_frame.pack(fill='x', pady=(0, 5))
        tk.Label(system_frame, text="系统制造商:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.system_manufacturer = tk.StringVar()
        system_man_entry = tk.Entry(system_frame, textvariable=self.system_manufacturer, width=20,
                                  bg=self.entry_bg, fg=self.entry_fg)
        system_man_entry.pack(side='left', padx=5)
        tk.Label(system_frame, text="(例如: Dell Inc.)", bg=self.bg_color, fg='gray').pack(side='left')

        product_frame = tk.Frame(smbios_group, bg=self.bg_color)
        product_frame.pack(fill='x', pady=(0, 5))
        tk.Label(product_frame, text="产品名称:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.system_product_name = tk.StringVar()
        product_entry = tk.Entry(product_frame, textvariable=self.system_product_name, width=30,
                               bg=self.entry_bg, fg=self.entry_fg)
        product_entry.pack(side='left', padx=5)
        tk.Label(product_frame, text="(例如: OptiPlex 7090)", bg=self.bg_color, fg='gray').pack(side='left')

        version_frame = tk.Frame(smbios_group, bg=self.bg_color)
        version_frame.pack(fill='x', pady=(0, 5))
        tk.Label(version_frame, text="系统版本:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.system_version = tk.StringVar()
        version_entry = tk.Entry(version_frame, textvariable=self.system_version, width=20,
                               bg=self.entry_bg, fg=self.entry_fg)
        version_entry.pack(side='left', padx=5)
        tk.Label(version_frame, text="(例如: 1.0)", bg=self.bg_color, fg='gray').pack(side='left')

        serial_frame = tk.Frame(smbios_group, bg=self.bg_color)
        serial_frame.pack(fill='x', pady=(0, 5))
        tk.Label(serial_frame, text="系统序列号:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.system_serial_number = tk.StringVar()
        serial_entry = tk.Entry(serial_frame, textvariable=self.system_serial_number, width=30,
                            bg=self.entry_bg, fg=self.entry_fg)
        serial_entry.pack(side='left', padx=5)
        tk.Label(serial_frame, text="(例如: ABC123456789)", bg=self.bg_color, fg='gray').pack(side='left')

        system_uuid_frame = tk.Frame(smbios_group, bg=self.bg_color)
        system_uuid_frame.pack(fill='x', pady=(0, 5))
        tk.Label(system_uuid_frame, text="系统UUID:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.system_uuid = tk.StringVar(value=str(uuid.uuid4()))
        system_uuid_entry = tk.Entry(system_uuid_frame, textvariable=self.system_uuid, width=40,
                                  bg=self.entry_bg, fg=self.entry_fg)
        system_uuid_entry.pack(side='left', padx=5)
        tk.Button(
            system_uuid_frame, text="生成", command=lambda: self.system_uuid.set(str(uuid.uuid4())),
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)

        # 主板信息
        board_frame = tk.Frame(smbios_group, bg=self.bg_color)
        board_frame.pack(fill='x', pady=(0, 5))
        tk.Label(board_frame, text="主板制造商:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.baseboard_manufacturer = tk.StringVar()
        board_man_entry = tk.Entry(board_frame, textvariable=self.baseboard_manufacturer, width=20,
                                 bg=self.entry_bg, fg=self.entry_fg)
        board_man_entry.pack(side='left', padx=5)
        tk.Label(board_frame, text="(例如: Dell Inc.)", bg=self.bg_color, fg='gray').pack(side='left')

        board_product_frame = tk.Frame(smbios_group, bg=self.bg_color)
        board_product_frame.pack(fill='x', pady=(0, 5))
        tk.Label(board_product_frame, text="主板产品名称:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.baseboard_product_name = tk.StringVar()
        board_product_entry = tk.Entry(board_product_frame, textvariable=self.baseboard_product_name, width=30,
                                   bg=self.entry_bg, fg=self.entry_fg)
        board_product_entry.pack(side='left', padx=5)
        tk.Label(board_product_frame, text="(例如: 0C2XKD)", bg=self.bg_color, fg='gray').pack(side='left')

        board_serial_frame = tk.Frame(smbios_group, bg=self.bg_color)
        board_serial_frame.pack(fill='x', pady=(0, 5))
        tk.Label(board_serial_frame, text="主板序列号:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.baseboard_serial_number = tk.StringVar()
        board_serial_entry = tk.Entry(board_serial_frame, textvariable=self.baseboard_serial_number, width=30,
                                   bg=self.entry_bg, fg=self.entry_fg)
        board_serial_entry.pack(side='left', padx=5)
        tk.Label(board_serial_frame, text="(例如: /ABC123456789/)", bg=self.bg_color, fg='gray').pack(side='left')

        # 机箱信息
        chassis_frame = tk.Frame(smbios_group, bg=self.bg_color)
        chassis_frame.pack(fill='x', pady=(0, 5))
        tk.Label(chassis_frame, text="机箱制造商:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.chassis_manufacturer = tk.StringVar()
        chassis_man_entry = tk.Entry(chassis_frame, textvariable=self.chassis_manufacturer, width=20,
                                  bg=self.entry_bg, fg=self.entry_fg)
        chassis_man_entry.pack(side='left', padx=5)
        tk.Label(chassis_frame, text="(例如: Dell Inc.)", bg=self.bg_color, fg='gray').pack(side='left')

        chassis_type_frame = tk.Frame(smbios_group, bg=self.bg_color)
        chassis_type_frame.pack(fill='x', pady=(0, 5))
        tk.Label(chassis_type_frame, text="机箱类型:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.chassis_type = tk.StringVar()
        chassis_type_combo = ttk.Combobox(
            chassis_type_frame, textvariable=self.chassis_type,
            values=["Desktop", "Low Profile Desktop", "Mini Tower", "Tower", "Portable", "Laptop", "Notebook", "Hand Held", "Docking Station", "All In One", "Sub Notebook", "Space-saving", "Lunch Box", "Main Server Chassis", "Expansion Chassis", "SubChassis", "Bus Expansion Chassis", "Peripheral Chassis", "RAID Chassis", "Rack Mount Chassis"], state='readonly', width=15
        )
        chassis_type_combo.pack(side='left', padx=5)

        # 杂项配置
        misc_group = tk.LabelFrame(
            scrollable_frame, text="杂项配置", bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        misc_group.pack(fill='x', pady=(0, 10))

        # UUID
        uuid_frame = tk.Frame(misc_group, bg=self.bg_color)
        uuid_frame.pack(fill='x', pady=(0, 5))
        tk.Label(uuid_frame, text="UUID:", bg=self.bg_color, fg=self.fg_color).pack(side='left')
        self.vm_uuid = tk.StringVar(value=str(uuid.uuid4()))
        uuid_entry = tk.Entry(uuid_frame, textvariable=self.vm_uuid, width=40,
                           bg=self.entry_bg, fg=self.entry_fg)
        uuid_entry.pack(side='left', padx=5)
        tk.Button(
            uuid_frame, text="生成", command=lambda: self.vm_uuid.set(str(uuid.uuid4())),
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        
        # 高级选项
        options_frame = tk.Frame(misc_group, bg=self.bg_color)
        options_frame.pack(fill='x', pady=(0, 5))
        
        self.vmport = tk.BooleanVar()
        vmport_check = tk.Checkbutton(
            options_frame, text="启用VMPORT", variable=self.vmport,
            bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color
        )
        vmport_check.pack(side='left', padx=5)
        
        self.kernel_irqchip = tk.BooleanVar()
        kernel_irqchip_check = tk.Checkbutton(
            options_frame, text="启用Kernel IRQCHIP", variable=self.kernel_irqchip,
            bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color
        )
        kernel_irqchip_check.pack(side='left', padx=5)
        
        self.dump_guest_core = tk.BooleanVar()
        dump_core_check = tk.Checkbutton(
            options_frame, text="转储客户机核心", variable=self.dump_guest_core,
            bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color
        )
        dump_core_check.pack(side='left', padx=5)
        
        self.mem_merge = tk.BooleanVar(value=True)
        mem_merge_check = tk.Checkbutton(
            options_frame, text="启用内存合并", variable=self.mem_merge,
            bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color
        )
        mem_merge_check.pack(side='left', padx=5)
        
        self.hmat = tk.BooleanVar()
        hmat_check = tk.Checkbutton(
            options_frame, text="启用HMAT", variable=self.hmat,
            bg=self.bg_color, fg=self.fg_color, selectcolor=self.bg_color
        )
        hmat_check.pack(side='left', padx=5)

    def setup_advanced_config(self, parent):
        """设置高级配置界面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 快照配置
        snap_group = tk.LabelFrame(
            frame, text=tr('snapshot'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        snap_group.pack(fill='x', pady=(0, 10))
        
        tk.Checkbutton(
            snap_group, text=tr('enable_snapshot'), variable=self.enable_snapshot,
            bg=self.bg_color, fg=self.fg_color
        ).pack(anchor='w')
        
        tk.Label(snap_group, text=tr('snapshot_name'), bg=self.bg_color, fg=self.fg_color).pack(anchor='w')
        tk.Entry(snap_group, textvariable=self.snapshot_name, width=30,
                bg=self.entry_bg, fg=self.entry_fg).pack(anchor='w', pady=5)
        
        # 其他高级选项
        other_group = tk.LabelFrame(
            frame, text=tr('other_options'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        other_group.pack(fill='x')
        
        tk.Label(other_group, text=tr('extra_params'), bg=self.bg_color, fg=self.fg_color).pack(anchor='w')
        tk.Entry(other_group, textvariable=self.extra_params, width=80,
                bg=self.entry_bg, fg=self.entry_fg).pack(fill='x', pady=5)
    
    def setup_shared_folder_config(self, parent):
        """设置共享文件夹配置界面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 共享文件夹配置
        shared_group = tk.LabelFrame(
            frame, text=tr('shared_folder'), bg=self.bg_color, 
            font=('Arial', 10, 'bold'), padx=10, pady=10
        )
        shared_group.pack(fill='both', expand=True)
        
        # 启用共享
        enable_frame = tk.Frame(shared_group, bg=self.bg_color)
        enable_frame.pack(fill='x', pady=(0, 10))
        
        tk.Checkbutton(
            enable_frame, text=tr('enable_shared'), variable=self.enable_shared_folder,
            bg=self.bg_color, fg=self.fg_color, command=self.toggle_shared_folder
        ).pack(side='left')
        
        # 共享路径
        path_frame = tk.Frame(shared_group, bg=self.bg_color)
        path_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(path_frame, text=tr('shared_path'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        path_entry = tk.Entry(path_frame, textvariable=self.shared_folder_path, width=60,
                            bg=self.entry_bg, fg=self.entry_fg)
        path_entry.pack(side='left', padx=5)
        
        tk.Button(
            path_frame, text=tr('browse'), command=self.browse_shared_folder,
            bg=self.button_bg, fg=self.button_fg, relief='flat'
        ).pack(side='left', padx=5)
        tk.Button(
            path_frame, text=tr('preview'), command=lambda: self.show_path_preview(self.shared_folder_path.get()),
            bg='#9b59b6', fg='white', relief='flat'
        ).pack(side='left', padx=5)
        
        # 共享标签
        tag_frame = tk.Frame(shared_group, bg=self.bg_color)
        tag_frame.pack(fill='x', pady=(0, 10))
        
        tk.Label(tag_frame, text=tr('shared_tag'), bg=self.bg_color, fg=self.fg_color).pack(side='left')
        tk.Entry(tag_frame, textvariable=self.shared_folder_tag, width=20,
               bg=self.entry_bg, fg=self.entry_fg).pack(side='left', padx=5)
        
        # 使用说明
        help_frame = tk.Frame(shared_group, bg=self.bg_color)
        help_frame.pack(fill='x', pady=(10, 0))
        
        help_text = tr('shared_folder_help')
        tk.Label(
            help_frame, text=help_text, 
            justify='left', bg=self.bg_color, fg=self.fg_color,
            anchor='w', wraplength=550
        ).pack(fill='x')
    
    def setup_about_page(self, parent):
        """设置关于页面"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 标题
        title_frame = tk.Frame(frame, bg=self.bg_color)
        title_frame.pack(fill='x', pady=(20, 10))
        
        tk.Label(
            title_frame, text=tr('app_title'), 
            font=('Arial', 24, 'bold'), bg=self.bg_color, fg=self.fg_color
        ).pack()
        
        tk.Label(
            title_frame, text=tr('app_description'), 
            font=('Arial', 12), bg=self.bg_color, fg=self.fg_color
        ).pack()
        
        # 分隔线
        ttk.Separator(frame, orient='horizontal').pack(fill='x', pady=10)
        
        # 描述
        desc_frame = tk.Frame(frame, bg=self.bg_color)
        desc_frame.pack(fill='x', pady=10)
        
        desc_text = (
            tr('developers') + "\n" +
            "  - Bilibili: scicat科技猫\n" +
            "  - Bilibili: 本周婆の\n" +
            "  - Bilibili: -价值5个硬币的昵称-\n\n" +
            tr('disclaimer')
        )
        
        tk.Label(
            desc_frame, text=desc_text, 
            justify='left', bg=self.bg_color, fg=self.fg_color, wraplength=600
        ).pack()
        
        # 开源地址
        repo_frame = tk.Frame(frame, bg=self.bg_color)
        repo_frame.pack(fill='x', pady=10)
        
        tk.Label(
            repo_frame, text=tr('repo'), 
            font=('Arial', 12, 'bold'), bg=self.bg_color, fg=self.fg_color
        ).pack(anchor='w')
        
        url = "https://gitee.com/scicat-team/vmboxy-pc"
        link = tk.Label(
            repo_frame, text=url, 
            fg='blue', cursor='hand2', bg=self.bg_color
        )
        link.pack(anchor='w', pady=5)
        link.bind('<Button-1>', lambda e: webbrowser.open(url))
        
        # 版权信息
        copyright_frame = tk.Frame(frame, bg=self.bg_color)
        copyright_frame.pack(fill='x', pady=(20, 0))
        
        tk.Label(
            copyright_frame, text=tr('copyright'), 
            font=('Arial', 10), bg=self.bg_color, fg=self.fg_color
        ).pack()
    
    def setup_log_console(self, parent):
        """设置日志控制台"""
        frame = tk.Frame(parent, bg=self.bg_color)
        frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 日志显示区域
        self.log_text = scrolledtext.ScrolledText(
            frame, wrap=tk.WORD, width=80, height=25,
            bg='#2c3e50', fg='#ecf0f1', insertbackground='white'
        )
        self.log_text.pack(fill='both', expand=True)
        self.log_text.config(state='disabled')
        
        # 日志按钮
        button_frame = tk.Frame(frame, bg=self.bg_color)
        button_frame.pack(fill='x', pady=(10, 0))
        
        tk.Button(
            button_frame, text=tr('clear_log'), command=self.clear_log,
            bg='#e74c3c', fg='white', relief='flat'
        ).pack(side='left', padx=5)
        
        tk.Button(
            button_frame, text=tr('save_log'), command=self.save_log,
            bg='#3498db', fg='white', relief='flat'
        ).pack(side='left', padx=5)
    
    # ==================== 新增功能方法 ====================
    
    def show_path_preview(self, path):
        """显示路径预览"""
        if not path:
            return
        
        # 创建预览窗口
        self.preview_window = Toplevel(self)
        self.preview_window.title(tr('preview'))
        self.preview_window.geometry("400x300")
        self.preview_window.transient(self)
        self.preview_window.grab_set()
        
        # 显示路径信息
        frame = tk.Frame(self.preview_window)
        frame.pack(fill='both', expand=True, padx=10, pady=10)
        
        tk.Label(frame, text=tr('preview_path', path), 
                font=('Arial', 10), wraplength=380).pack(anchor='w', pady=5)
        
        # 如果是磁盘镜像，显示额外信息
        if path.lower().endswith(('.qcow2', '.img', '.raw', '.vdi', '.vmdk')):
            tk.Label(frame, text="磁盘信息:", font=('Arial', 10, 'bold')).pack(anchor='w', pady=5)
            info = get_disk_info(path)
            if info:
                info_text = scrolledtext.ScrolledText(frame, wrap=tk.WORD, height=10)
                info_text.pack(fill='both', expand=True, pady=5)
                info_text.insert('1.0', info)
                info_text.config(state='disabled')
    
    def hide_path_preview(self):
        """隐藏路径预览"""
        if hasattr(self, 'preview_window') and self.preview_window.winfo_exists():
            self.preview_window.destroy()
    
    # ==================== 设置相关方法 ====================
    
    def change_language(self, event=None):
        """切换语言"""
        new_lang = self.lang_var.get()
        global CURRENT_LANG
        CURRENT_LANG = new_lang
        
        # 更新设置
        self.settings['language'] = new_lang
        save_settings(self.settings)
        
        # 重新加载界面
        self.log(tr('language_changed', new_lang))
        self.destroy()
        app = VMBoxyGUI()
        app.mainloop()
    
    def change_theme(self, event=None):
        """切换主题"""
        new_theme = self.theme_var.get()
        self.theme = new_theme
        self.apply_theme(new_theme)
        
        # 更新设置
        self.settings['theme'] = new_theme
        save_settings(self.settings)
        
        self.log(tr('theme_changed', new_theme))
    
    def change_log_level(self, event=None):
        """切换日志级别"""
        new_level = self.log_level_var.get()
        
        # 更新日志级别
        logger.setLevel(new_level)
        for handler in logger.handlers:
            handler.setLevel(new_level)
        
        # 更新设置
        self.settings['log_level'] = new_level
        save_settings(self.settings)
        
        self.log(tr('log_level_changed', new_level))
    
    def change_auto_start(self):
        """切换自动启动设置"""
        auto_start = self.auto_start_var.get()
        
        # 更新设置
        self.settings['auto_start_last_vm'] = auto_start
        save_settings(self.settings)
        
        self.log(tr('auto_start_changed', auto_start))
    
    def save_settings(self):
        """保存所有设置"""
        # 确保所有设置都是最新的
        self.settings['language'] = self.lang_var.get()
        self.settings['theme'] = self.theme_var.get()
        self.settings['log_level'] = self.log_level_var.get()
        self.settings['auto_start_last_vm'] = self.auto_start_var.get()
        
        if save_settings(self.settings):
            messagebox.showinfo(tr('settings_saved'), tr('settings_saved'))
            self.log(tr('settings_saved'))
    
    def reset_settings(self):
        """重置设置为默认值"""
        default_settings = {
            'language': 'zh_CN',
            'theme': 'default',
            'log_level': 'INFO',
            'auto_start_last_vm': False,
            'last_vm': ''
        }
        
        self.settings = default_settings
        save_settings(default_settings)
        
        # 重新加载应用
        self.log(tr('settings_reset'))
        self.destroy()
        app = VMBoxyGUI()
        app.mainloop()
    
    def auto_start_last_vm(self):
        """自动启动上次使用的虚拟机"""
        last_vm = self.settings.get('last_vm', '')
        if not last_vm:
            return
        
        # 查找虚拟机
        found = False
        for i, vm in enumerate(self.vm_list):
            if vm['file'] == last_vm:
                self.vm_listbox.selection_clear(0, 'end')
                self.vm_listbox.selection_set(i)
                self.on_vm_selected(None)
                self.start_vm()
                found = True
                break
        
        if not found:
            self.log(tr('vm_not_found'))
    
    # ==================== 虚拟机列表管理 ====================
    
    def load_vm_list(self):
        """加载虚拟机列表"""
        self.vm_list = []
        self.vm_listbox.delete(0, 'end')
        self.current_vm = None  # 重置当前选中的虚拟机
        
        # 添加一个空的默认虚拟机
        self.vm_list.append({
            'name': "无虚拟机",
            'file': "empty.json"
        })
        self.vm_listbox.insert('end', "无虚拟机")
        
        # 加载真实虚拟机
        for file in VM_CONFIG_DIR.glob('*.json'):
            try:
                with open(file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    vm_name = config.get('vm_name', file.stem)
                    self.vm_list.append({
                        'name': vm_name,
                        'file': file.name
                    })
                    self.vm_listbox.insert('end', vm_name)
            except:
                logger.error(f"加载虚拟机配置失败: {file}")
        
        # 默认选中第一个（空的虚拟机）
        if self.vm_list:
            self.vm_listbox.selection_set(0)
            self.on_vm_selected(None)
    
    def on_vm_selected(self, event):
        """当虚拟机被选中时"""
        selection = self.vm_listbox.curselection()
        if not selection:
            return
            
        index = selection[0]
        if index < len(self.vm_list):
            vm = self.vm_list[index]
            self.current_vm = vm
            
            # 如果是空的虚拟机，不加载任何配置
            if vm['name'] == "无虚拟机":
                self.status_bar.config(text=tr('no_vm_selected'))
                return
                
            self.load_vm_config(vm['file'])
            self.status_bar.config(text=tr('vm_loaded', vm['name']))
    
    def create_vm(self):
        """创建新虚拟机"""
        dialog = tk.Toplevel(self)
        dialog.title(tr('create_vm_title'))
        dialog.geometry("400x200")
        dialog.configure(bg=self.bg_color)
        dialog.transient(self)
        dialog.grab_set()
        
        tk.Label(dialog, text=tr('vm_name'), bg=self.bg_color, fg=self.fg_color).pack(pady=10)
        vm_name = tk.StringVar()
        entry = tk.Entry(dialog, textvariable=vm_name, width=30, 
                         bg=self.entry_bg, fg=self.entry_fg)
        entry.pack(pady=5)
        entry.focus()
        
        def save():
            name = vm_name.get().strip()
            if not name:
                messagebox.showerror(tr('vm_name_empty'), tr('vm_name_empty'))
                return
                
            # 检查是否已存在
            for vm in self.vm_list:
                if vm['name'] == name:
                    messagebox.showerror(tr('vm_exists'), tr('vm_exists'))
                    return
                    
            # 创建新配置
            config = {
                'vm_name': name,
                'qemu_path': self.qemu_path.get(),
                'machine_type': self.machine_type.get(),
                'cpu_model': self.cpu_model.get(),
                'memory_size': self.memory_size.get(),
                'vga_type': self.vga_type.get(),
                'disk_path': self.disk_path.get(),
                'disk_interface': self.disk_interface.get(),  # 新增
                'iso_path': self.iso_path.get(),
                'fda_path': self.fda_path.get(),
                'bios_path': self.bios_path.get(),  # BIOS文件路径
                'network_model': self.network_model.get(),
                'mac_address': self.mac_address.get(),
                'dns_server': self.dns_server.get(),
                'enable_usb': self.enable_usb.get(),
                'accel_type': self.accel_type.get(),
                'no_hpet': self.no_hpet.get(),
                'boot_order': self.boot_order.get(),
                'enable_snapshot': self.enable_snapshot.get(),
                'snapshot_name': self.snapshot_name.get(),
                'extra_params': self.extra_params.get(),
                'port_forwards': self.port_forwards,
                'enable_shared_folder': self.enable_shared_folder.get(),
                'shared_folder_path': self.shared_folder_path.get(),
                'shared_folder_tag': self.shared_folder_tag.get(),
                # SMBIOS配置
                'bios_vendor': self.bios_vendor.get(),
                'bios_version': self.bios_version.get(),
                'bios_release_date': self.bios_release_date.get(),
                'system_manufacturer': self.system_manufacturer.get(),
                'system_product_name': self.system_product_name.get(),
                'system_version': self.system_version.get(),
                'system_serial_number': self.system_serial_number.get(),
                'system_uuid': self.system_uuid.get(),
                'baseboard_manufacturer': self.baseboard_manufacturer.get(),
                'baseboard_product_name': self.baseboard_product_name.get(),
                'baseboard_serial_number': self.baseboard_serial_number.get(),
                'chassis_manufacturer': self.chassis_manufacturer.get(),
                'chassis_type': self.chassis_type.get()
            }
            
            # 保存配置文件
            filename = VM_CONFIG_DIR / f"{name}.json"
            try:
                with open(filename, 'w', encoding='utf-8') as f:
                    json.dump(config, f, indent=2, ensure_ascii=False)
                self.log(tr('vm_created', name))
                self.load_vm_list()
                dialog.destroy()
            except Exception as e:
                messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
        
        button_frame = tk.Frame(dialog, bg=self.bg_color)
        button_frame.pack(pady=10)
        
        tk.Button(
            button_frame, text="确定", command=save,
            bg='#27ae60', fg='white', width=10
        ).pack(side='left', padx=10)
        
        tk.Button(
            button_frame, text="取消", command=dialog.destroy,
            bg='#e74c3c', fg='white', width=10
        ).pack(side='left', padx=10)
    
    def delete_vm(self):
        """删除虚拟机"""
        if not self.current_vm:
            messagebox.showinfo(tr('select_vm'), tr('select_vm'))
            return
            
        # 检查是否是空的虚拟机
        if self.current_vm['name'] == "无虚拟机":
            messagebox.showinfo(tr('no_vm_selected'), tr('no_vm_selected'))
            return
            
        name = self.current_vm['name']
        if not messagebox.askyesno(tr('delete_confirm'), tr('delete_prompt', name)):
            return
            
        try:
            filename = VM_CONFIG_DIR / self.current_vm['file']
            os.remove(filename)
            self.log(tr('vm_deleted', name))
            self.current_vm = None
            self.load_vm_list()
        except Exception as e:
            messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
    
    def rename_vm(self):
        """重命名虚拟机"""
        if not self.current_vm:
            messagebox.showinfo(tr('select_vm'), tr('select_vm'))
            return
            
        # 检查是否是空的虚拟机
        if self.current_vm['name'] == "无虚拟机":
            messagebox.showinfo(tr('no_vm_selected'), tr('no_vm_selected'))
            return
            
        old_name = self.current_vm['name']
        old_file = self.current_vm['file']
        
        dialog = tk.Toplevel(self)
        dialog.title(tr('rename_title'))
        dialog.geometry("400x200")
        dialog.configure(bg=self.bg_color)
        dialog.transient(self)
        dialog.grab_set()
        
        tk.Label(dialog, text=tr('new_name'), bg=self.bg_color, fg=self.fg_color).pack(pady=10)
        new_name = tk.StringVar(value=old_name)
        entry = tk.Entry(dialog, textvariable=new_name, width=30,
                         bg=self.entry_bg, fg=self.entry_fg)
        entry.pack(pady=5)
        entry.focus()
        entry.select_range(0, 'end')
        
        def save():
            name = new_name.get().strip()
            if not name:
                messagebox.showerror(tr('vm_name_empty'), tr('vm_name_empty'))
                return
                
            if name == old_name:
                dialog.destroy()
                return
                
            # 检查是否已存在
            for vm in self.vm_list:
                if vm['name'] == name:
                    messagebox.showerror(tr('name_exists'), tr('name_exists'))
                    return
                    
            # 重命名配置文件
            old_path = VM_CONFIG_DIR / old_file
            new_path = VM_CONFIG_DIR / f"{name}.json"
            
            try:
                # 加载旧配置
                with open(old_path, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                
                # 更新名称
                config['vm_name'] = name
                
                # 保存新配置
                with open(new_path, 'w', encoding='utf-8') as f:
                    json.dump(config, f, indent=2, ensure_ascii=False)
                
                # 删除旧配置
                os.remove(old_path)
                
                self.log(tr('vm_renamed', old_name, name))
                self.load_vm_list()
                dialog.destroy()
            except Exception as e:
                messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
        
        button_frame = tk.Frame(dialog, bg=self.bg_color)
        button_frame.pack(pady=10)
        
        tk.Button(
            button_frame, text="确定", command=save,
            bg='#27ae60', fg='white', width=10
        ).pack(side='left', padx=10)
        
        tk.Button(
            button_frame, text="取消", command=dialog.destroy,
            bg='#e74c3c', fg='white', width=10
        ).pack(side='left', padx=10)
    
    def load_vm_config(self, filename):
        """加载虚拟机配置"""
        try:
            filepath = VM_CONFIG_DIR / filename
            with open(filepath, 'r', encoding='utf-8') as f:
                config = json.load(f)
                
            self.vm_name.set(config.get('vm_name', ''))
            self.qemu_path.set(config.get('qemu_path', ''))
            self.machine_type.set(config.get('machine_type', 'q35'))
            self.cpu_model.set(config.get('cpu_model', 'host'))
            self.memory_size.set(config.get('memory_size', '2G'))
            self.vga_type.set(config.get('vga_type', 'vmware'))
            self.disk_path.set(config.get('disk_path', ''))
            self.disk_interface.set(config.get('disk_interface', 'ide'))  # 新增
            self.iso_path.set(config.get('iso_path', ''))
            self.fda_path.set(config.get('fda_path', ''))
            self.bios_path.set(config.get('bios_path', ''))  # BIOS文件路径
            self.network_model.set(config.get('network_model', 'virtio-net-pci'))
            self.mac_address.set(config.get('mac_address', generate_mac_address()))
            self.dns_server.set(config.get('dns_server', '8.8.8.8'))
            self.enable_usb.set(config.get('enable_usb', True))
            self.accel_type.set(config.get('accel_type', 'kvm'))
            self.no_hpet.set(config.get('no_hpet', True))
            self.boot_order.set(config.get('boot_order', 'cd'))
            self.enable_snapshot.set(config.get('enable_snapshot', False))
            self.snapshot_name.set(config.get('snapshot_name', 'snapshot1'))
            self.extra_params.set(config.get('extra_params', ''))
            self.port_forwards = config.get('port_forwards', [])
            self.enable_shared_folder.set(config.get('enable_shared_folder', False))
            self.shared_folder_path.set(config.get('shared_folder_path', str(SHARED_DIR)))
            self.shared_folder_tag.set(config.get('shared_folder_tag', 'shared'))
            # SMBIOS配置
            self.bios_vendor.set(config.get('bios_vendor', ''))
            self.bios_version.set(config.get('bios_version', ''))
            self.bios_release_date.set(config.get('bios_release_date', ''))
            self.system_manufacturer.set(config.get('system_manufacturer', ''))
            self.system_product_name.set(config.get('system_product_name', ''))
            self.system_version.set(config.get('system_version', ''))
            self.system_serial_number.set(config.get('system_serial_number', ''))
            self.system_uuid.set(config.get('system_uuid', str(uuid.uuid4())))
            self.baseboard_manufacturer.set(config.get('baseboard_manufacturer', ''))
            self.baseboard_product_name.set(config.get('baseboard_product_name', ''))
            self.baseboard_serial_number.set(config.get('baseboard_serial_number', ''))
            self.chassis_manufacturer.set(config.get('chassis_manufacturer', ''))
            self.chassis_type.set(config.get('chassis_type', ''))
            
            # 更新端口转发列表
            if hasattr(self, 'forward_listbox'):
                self.forward_listbox.delete(0, 'end')
                for rule in self.port_forwards:
                    self.forward_listbox.insert('end', rule)
                    
            # 更新加速选项
            self.accel_options = detect_accel_options(self.qemu_path.get())
            self.cpu_features = detect_cpu_features(self.qemu_path.get())
            self.update_accel_options()
                    
            self.log(tr('vm_loaded', filename))
            
        except Exception as e:
            messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
    
    def save_config(self):
        """保存当前配置"""
        if not self.current_vm:
            messagebox.showinfo(tr('select_vm'), tr('select_vm'))
            return
            
        # 检查是否是空的虚拟机
        if self.current_vm['name'] == "无虚拟机":
            messagebox.showinfo(tr('no_vm_selected'), tr('no_vm_selected'))
            return
            
        config = {
            'vm_name': self.vm_name.get(),
            'qemu_path': self.qemu_path.get(),
            'machine_type': self.machine_type.get(),
            'cpu_model': self.cpu_model.get(),
            'memory_size': self.memory_size.get(),
            'vga_type': self.vga_type.get(),
            'disk_path': self.disk_path.get(),
            'disk_interface': self.disk_interface.get(),  # 新增
            'iso_path': self.iso_path.get(),
            'fda_path': self.fda_path.get(),
            'network_model': self.network_model.get(),
            'mac_address': self.mac_address.get(),
            'dns_server': self.dns_server.get(),
            'enable_usb': self.enable_usb.get(),
            'accel_type': self.accel_type.get(),
            'no_hpet': self.no_hpet.get(),
            'boot_order': self.boot_order.get(),
            'enable_snapshot': self.enable_snapshot.get(),
            'snapshot_name': self.snapshot_name.get(),
            'extra_params': self.extra_params.get(),
            'port_forwards': self.port_forwards,
            'enable_shared_folder': self.enable_shared_folder.get(),
            'shared_folder_path': self.shared_folder_path.get(),
            'shared_folder_tag': self.shared_folder_tag.get(),
            'bios_vendor': self.bios_vendor.get(),
            'bios_version': self.bios_version.get(),
            'bios_release_date': self.bios_release_date.get(),
            'system_manufacturer': self.system_manufacturer.get(),
            'system_product_name': self.system_product_name.get(),
            'system_version': self.system_version.get(),
            'system_serial_number': self.system_serial_number.get(),
            'system_uuid': self.system_uuid.get(),
            'baseboard_manufacturer': self.baseboard_manufacturer.get(),
            'baseboard_product_name': self.baseboard_product_name.get(),
            'baseboard_serial_number': self.baseboard_serial_number.get(),
            'chassis_manufacturer': self.chassis_manufacturer.get(),
            'chassis_type': self.chassis_type.get()
        }
        
        try:
            filename = VM_CONFIG_DIR / self.current_vm['file']
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(config, f, indent=2, ensure_ascii=False)
            self.log(tr('config_saved'))
            messagebox.showinfo(tr('config_saved'), tr('config_saved'))
            
            # 更新设置中的最后使用的虚拟机
            self.settings['last_vm'] = self.current_vm['file']
            save_settings(self.settings)
        except Exception as e:
            messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
    
    def load_config(self):
        """加载配置文件"""
        filename = filedialog.askopenfilename(
            initialdir=VM_CONFIG_DIR,
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")]
        )
        
        if filename and os.path.exists(filename):
            try:
                with open(filename, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    
                # 创建新的虚拟机条目
                vm_name = config.get('vm_name', Path(filename).stem)
                new_file = f"{vm_name}.json"
                
                # 检查是否已存在
                exists = False
                for vm in self.vm_list:
                    if vm['name'] == vm_name:
                        exists = True
                        break
                
                if not exists:
                    # 保存到虚拟机配置目录
                    new_path = VM_CONFIG_DIR / new_file
                    with open(new_path, 'w', encoding='utf-8') as f:
                        json.dump(config, f, indent=2, ensure_ascii=False)
                    
                    self.log(tr('vm_imported', vm_name))
                    self.load_vm_list()
                    
                    # 选择新导入的虚拟机
                    for i, vm in enumerate(self.vm_list):
                        if vm['name'] == vm_name:
                            self.vm_listbox.selection_clear(0, 'end')
                            self.vm_listbox.selection_set(i)
                            self.on_vm_selected(None)
                            break
                else:
                    messagebox.showinfo(tr('vm_exists_import', vm_name), tr('vm_exists_import', vm_name))
                    
            except Exception as e:
                messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
    
    # ==================== 文件浏览方法 ====================
    
    def detect_qemu(self):
        """自动检测QEMU路径"""
        path = find_qemu_executable()
        if path:
            self.qemu_path.set(path)
            self.log(tr('qemu_detected', path))
            # 更新加速选项
            self.accel_options = detect_accel_options(path)
            self.cpu_features = detect_cpu_features(path)
            self.update_accel_options()
            messagebox.showinfo(tr('qemu_detected', path), tr('qemu_detected', path))
        else:
            messagebox.showerror(tr('qemu_not_found'), tr('qemu_not_found'))
    
    def find_qemu_in_directory(self, directory):
        """在目录中查找QEMU可执行文件，支持x86_64、i386、ARM架构"""
        if not directory or not os.path.isdir(directory):
            return None
            
        system = platform.system()
        qemu_executables = []
        
        # 根据系统定义可能的QEMU可执行文件名
        if system == 'Windows':
            patterns = [
                'qemu-system-x86_64.exe',
                'qemu-system-x86_64w.exe',
                'qemu-system-i386.exe',
                'qemu-system-i386w.exe',
                'qemu-system-aarch64.exe',
                'qemu-system-aarch64w.exe',
                'qemu-system-arm.exe',
                'qemu-system-armw.exe'
            ]
        else:
            patterns = [
                'qemu-system-x86_64',
                'qemu-system-i386',
                'qemu-system-aarch64',
                'qemu-system-arm'
            ]
        
        # 在目录中查找匹配的文件
        for pattern in patterns:
            full_path = os.path.join(directory, pattern)
            if os.path.isfile(full_path) and os.access(full_path, os.X_OK if system != 'Windows' else os.F_OK):
                qemu_executables.append(full_path)
        
        # 按优先级排序：x86_64 > aarch64 > arm > i386
        priority_order = {
            'x86_64': 1,
            'aarch64': 2,
            'arm': 3,
            'i386': 4
        }
        
        if qemu_executables:
            # 按优先级排序
            qemu_executables.sort(key=lambda x: priority_order.get(
                next((arch for arch in priority_order.keys() if arch in os.path.basename(x)), 'arm'), 5))
            return qemu_executables[0]
            
        return None
        
    def browse_qemu_path(self):
        """浏览QEMU文件夹并自动选择可执行文件"""
        dirname = filedialog.askdirectory(title=tr('select_qemu'))
        if dirname:
            qemu_path = self.find_qemu_in_directory(dirname)
            if qemu_path:
                self.qemu_path.set(qemu_path)
                self.log(tr('qemu_selected', qemu_path))
                # 更新加速选项
                self.accel_options = detect_accel_options(qemu_path)
                self.cpu_features = detect_cpu_features(qemu_path)
                self.update_accel_options()
            else:
                messagebox.showerror("错误", "在选择的文件夹中未找到有效的QEMU可执行文件")
            
    def browse_disk(self):
        """浏览磁盘镜像"""
        filename = filedialog.askopenfilename(
            title=tr('select_disk'),
            filetypes=[
                ("QEMU镜像", "*.qcow2 *.img *.raw"),
                ("所有文件", "*.*")
            ]
        )
        if filename:
            self.disk_path.set(filename)
            info = get_disk_info(filename)
            if info:
                self.log(tr('disk_selected', filename))
                
    def browse_iso(self):
        """浏览ISO镜像"""
        filename = filedialog.askopenfilename(
            title=tr('select_iso'),
            filetypes=[("ISO文件", "*.iso"), ("所有文件", "*.*")]
        )
        if filename:
            self.iso_path.set(filename)
            self.log(tr('iso_selected', filename))
            
    def browse_fda(self):
        """浏览软盘镜像文件"""
        filename = filedialog.askopenfilename(
            title="选择软盘镜像文件",
            filetypes=[("软盘镜像", "*.img *.ima"), ("所有文件", "*.*")]
        )
        if filename:
            self.fda_path.set(filename)
    
    def browse_bios_file(self):
        """浏览BIOS文件"""
        filename = filedialog.askopenfilename(
            title="选择BIOS文件",
            filetypes=[("BIOS文件", "*.fd *.bin *.rom"), ("所有文件", "*.*")]
        )
        if filename:
            self.bios_path.set(filename)
            self.log(tr('fda_selected', filename))
            
    def choose_new_disk_path(self):
        """选择新磁盘路径"""
        filename = filedialog.asksaveasfilename(
            title=tr('create_disk_title'),
            defaultextension=".qcow2",
            filetypes=[
                ("QCOW2镜像", "*.qcow2"),
                ("RAW镜像", "*.img"),
                ("所有文件", "*.*")
            ]
        )
        if filename:
            self.new_disk_path.set(filename)
            self.log(tr('new_disk_path'))
            
    def create_disk(self):
        """创建磁盘镜像"""
        path = self.new_disk_path.get()
        size = self.new_disk_size.get()
        format_type = self.new_disk_format.get()
        
        if not path:
            messagebox.showerror(tr('disk_path_empty'), tr('disk_path_empty'))
            return
            
        try:
            size_bytes = format_size(size)
            if size_bytes < 64 * 1024 * 1024:  # 最小64MB
                messagebox.showerror(tr('disk_size_min'), tr('disk_size_min'))
                return
                
            if create_disk_image(path, size, format_type):
                self.log(tr('disk_created', os.path.basename(path)))
                self.disk_path.set(path)
                messagebox.showinfo(tr('disk_created', os.path.basename(path)), tr('disk_created', os.path.basename(path)))
            else:
                messagebox.showerror(tr('disk_failed'), tr('disk_failed'))
                
        except ValueError:
            messagebox.showerror(tr('invalid_size'), tr('invalid_size'))
            
    def browse_shared_folder(self):
        """浏览共享文件夹路径"""
        dirname = filedialog.askdirectory(
            title=tr('select_disk'),
            initialdir=self.shared_folder_path.get()
        )
        if dirname:
            self.shared_folder_path.set(dirname)
            
    def toggle_shared_folder(self):
        """切换共享文件夹启用状态"""
        if self.enable_shared_folder.get():
            if not os.path.exists(self.shared_folder_path.get()):
                try:
                    os.makedirs(self.shared_folder_path.get(), exist_ok=True)
                    self.log(f"已创建共享文件夹: {self.shared_folder_path.get()}")
                except Exception as e:
                    self.log(f"创建共享文件夹失败: {e}")
                    messagebox.showerror("错误", f"创建共享文件夹失败: {e}")
                    self.enable_shared_folder.set(False)
    
    # ==================== 网络配置方法 ====================
    
    def generate_mac(self):
        """生成随机MAC地址"""
        self.mac_address.set(generate_mac_address())
        self.log("已生成新的MAC地址")
    
    def add_port_forward(self):
        """添加端口转发规则"""
        host = self.host_port.get().strip()
        guest = self.guest_port.get().strip()
        
        if host and guest:
            try:
                host_int = int(host)
                guest_int = int(guest)
                
                # 验证端口范围
                if host_int < 1 or host_int > 65535 or guest_int < 1 or guest_int > 65535:
                    messagebox.showerror(tr('port_number'), tr('port_number'))
                    return
                
                # 验证是否为特权端口
                if host_int < 1024:
                    if not messagebox.askyesno("警告", "主机端口小于1024可能需要管理员权限，继续吗？"):
                        return
                
                # 检查重复规则
                rule = f"{host_int}:{guest_int}"
                if rule in self.port_forwards:
                    messagebox.showinfo("提示", "该端口转发规则已存在")
                    return
                    
                self.port_forwards.append(rule)
                self.forward_listbox.insert('end', rule)
                self.host_port.set("")
                self.guest_port.set("")
                self.log(f"添加端口转发规则: {rule}")
            except ValueError:
                messagebox.showerror(tr('port_number'), tr('port_number'))
        else:
            messagebox.showerror("错误", "请输入主机端口和虚拟机端口")
                
    def remove_port_forward(self):
        """移除端口转发规则"""
        selection = self.forward_listbox.curselection()
        if selection:
            index = selection[0]
            rule = self.forward_listbox.get(index)
            self.port_forwards.remove(rule)
            self.forward_listbox.delete(index)
            
    # ==================== 日志方法 ====================
    
    def log(self, message):
        """添加日志信息"""
        if self.log_text:
            self.log_text.config(state='normal')
            timestamp = time.strftime("%H:%M:%S")
            self.log_text.insert('end', f"[{timestamp}] {message}\n")
            self.log_text.see('end')
            self.log_text.config(state='disabled')
            logger.info(message)
            
    def clear_log(self):
        """清空日志"""
        if self.log_text:
            self.log_text.config(state='normal')
            self.log_text.delete(1.0, 'end')
            self.log_text.config(state='disabled')
            self.log(tr('log_cleared'))
            
    def save_log(self):
        """保存日志到文件"""
        if self.log_text:
            filename = filedialog.asksaveasfilename(
                defaultextension=".log",
                filetypes=[("日志文件", "*.log"), ("文本文件", "*.txt")]
            )
            if filename:
                try:
                    with open(filename, 'w', encoding='utf-8') as f:
                        self.log_text.config(state='normal')
                        f.write(self.log_text.get(1.0, 'end'))
                        self.log_text.config(state='disabled')
                    self.log(tr('log_saved', filename))
                except Exception as e:
                    messagebox.showerror(tr('config_load_failed', str(e)), tr('config_load_failed', str(e)))
    
    # ==================== 菜单方法 ====================
    
    def show_file_menu(self):
        """显示文件菜单"""
        menu = tk.Menu(self, tearoff=0)
        menu.add_command(label=tr('save_config'), command=self.save_config)
        menu.add_command(label=tr('load_config'), command=self.load_config)
        menu.add_separator()
        menu.add_command(label="退出", command=self.destroy)
        menu.post(self.winfo_pointerx(), self.winfo_pointery())
    
    def show_vm_menu(self):
        """显示虚拟机菜单"""
        menu = tk.Menu(self, tearoff=0)
        menu.add_command(label=tr('new_vm'), command=self.create_vm)
        menu.add_command(label=tr('delete_vm'), command=self.delete_vm)
        menu.add_command(label=tr('rename_vm'), command=self.rename_vm)
        menu.add_separator()
        menu.add_command(label=tr('start_vm'), command=self.start_vm)
        menu.post(self.winfo_pointerx(), self.winfo_pointery())
    
    def show_help_menu(self):
        """显示帮助菜单"""
        menu = tk.Menu(self, tearoff=0)
        menu.add_command(label=tr('about'), command=lambda: self.notebook.select(6))
        menu.add_command(label=tr('repo'), command=lambda: webbrowser.open("https://gitee.com/scicat-team/vmboxy-pc"))
        menu.add_separator()
        menu.add_command(label=tr('log_console'), command=lambda: self.notebook.select(7))
        menu.add_command(label=tr('settings'), command=lambda: self.notebook.select(5))
        menu.post(self.winfo_pointerx(), self.winfo_pointery())
    
    # ==================== 虚拟机启动方法 ====================
    
    def start_vm(self):
        """启动虚拟机"""
        if not self.current_vm:
            messagebox.showinfo(tr('no_vm_selected'), tr('no_vm_selected'))
            return
            
        # 检查是否是空的虚拟机
        if self.current_vm['name'] == "无虚拟机":
            messagebox.showinfo(tr('no_vm_selected'), tr('no_vm_selected'))
            return
            
        if not self.qemu_path.get():
            messagebox.showerror(tr('qemu_missing'), tr('qemu_missing'))
            return
            
        if not os.path.exists(self.qemu_path.get()):
            messagebox.showerror(tr('qemu_not_found'), tr('qemu_not_found'))
            return
            
        # 验证QEMU可执行文件
        qemu_path = Path(self.qemu_path.get())
        if not qemu_path.is_file():
            messagebox.showerror(tr('qemu_not_found'), "QEMU路径不是有效的文件")
            return
            
        # 验证文件可执行权限（Windows下检查.exe扩展名）
        if self.system == 'Windows':
            if not qemu_path.suffix.lower() == '.exe':
                if not messagebox.askyesno("确认", "选择的文件可能不是QEMU可执行文件，是否继续？"):
                    return
        else:
            # Unix-like系统检查可执行权限
            if not os.access(qemu_path, os.X_OK):
                messagebox.showerror("错误", "QEMU文件没有执行权限")
                return
            
        if not self.disk_path.get() and not self.iso_path.get() and not self.fda_path.get():
            messagebox.showerror(tr('no_boot_device'), tr('no_boot_device'))
            return
            
        # 验证MAC地址
        if self.mac_address.get() and not validate_mac_address(self.mac_address.get()):
            messagebox.showerror(tr('mac_invalid'), tr('mac_invalid'))
            return
            
        # 构建命令
        cmd = [self.qemu_path.get()]
        
        # 基本配置
        cmd.extend(['-name', self.vm_name.get()])
        cmd.extend(['-machine', self.machine_type.get()])
        
        # CPU配置 - 使用高级配置或基础配置
        if hasattr(self, 'cpu_family') and self.cpu_family.get():
            # 使用B站教程的高级CPU配置
            cpu_config = self.cpu_model.get()
            
            # 添加CPU标识符配置
            if self.cpu_family.get():
                cpu_config += f",family={self.cpu_family.get()}"
            if self.cpu_model_num.get():
                cpu_config += f",model={self.cpu_model_num.get()}"
            if self.cpu_stepping.get():
                cpu_config += f",stepping={self.cpu_stepping.get()}"
            if self.cpu_vendor.get():
                cpu_config += f",vendor={self.cpu_vendor.get()}"
            if self.cpu_level.get():
                cpu_config += f",level={self.cpu_level.get()}"
            if self.cpu_xlevel.get():
                cpu_config += f",xlevel={self.cpu_xlevel.get()}"
            if self.cpu_uuid.get():
                cpu_config += f",uuid={self.cpu_uuid.get()}"
            if hasattr(self, 'cpu_model_id') and self.cpu_model_id.get():
                cpu_config += f",model_id='{self.cpu_model_id.get()}'"
            
            # 添加缓存配置
            if hasattr(self, 'cpu_l3cache') and self.cpu_l3cache.get():
                cpu_config += ",+l3-cache"
            
            cmd.extend(['-cpu', cpu_config])
        else:
            # 使用基础CPU配置
            cmd.extend(['-cpu', self.cpu_model.get()])
            
        # CPU拓扑配置（来自B站教程）
        if hasattr(self, 'cpu_sockets') and str(self.cpu_sockets.get()).strip():
            try:
                sockets = int(str(self.cpu_sockets.get()).strip())
                cores = int(str(self.cpu_cores.get()).strip()) if hasattr(self, 'cpu_cores') and str(self.cpu_cores.get()).strip() else 1
                threads = int(str(self.cpu_threads.get()).strip()) if hasattr(self, 'cpu_threads') and str(self.cpu_threads.get()).strip() else 1
                
                # 验证CPU配置合理性
                sockets = max(1, min(sockets, 8))  # 限制1-8个socket
                cores = max(1, min(cores, 128))  # 限制1-128个核心
                threads = max(1, min(threads, 2))  # 限制1-2个线程
                
                total_cpus = sockets * cores * threads
                if total_cpus > 256:
                    total_cpus = 256
                    self.log("警告: CPU总数超过256，已调整为256")
                
                cmd.extend(['-smp', f'{total_cpus},sockets={sockets},cores={cores},threads={threads}'])
            except ValueError:
                pass
        
        # 内存配置（来自B站教程）
        memory_str = str(self.memory_size.get()).strip()
        if not memory_str:
            memory_str = "2G"
        
        # 验证内存大小
        try:
            if memory_str.upper().endswith('G'):
                memory_gb = float(memory_str[:-1])
                if memory_gb < 0.5:
                    memory_gb = 0.5
                    self.log("警告: 内存大小小于0.5GB，已调整为0.5GB")
                elif memory_gb > 64:
                    memory_gb = 64
                    self.log("警告: 内存大小超过64GB，已调整为64GB")
                memory_str = f"{memory_gb}G"
            elif memory_str.upper().endswith('M'):
                memory_mb = float(memory_str[:-1])
                if memory_mb < 512:
                    memory_mb = 512
                    self.log("警告: 内存大小小于512MB，已调整为512MB")
                elif memory_mb > 65536:
                    memory_mb = 65536
                    self.log("警告: 内存大小超过64GB，已调整为64GB")
                memory_str = f"{memory_mb}M"
            else:
                # 默认使用GB
                memory_gb = max(0.5, min(float(memory_str), 64))
                memory_str = f"{memory_gb}G"
        except ValueError:
            memory_str = "2G"
            self.log("警告: 内存格式错误，已调整为2GB")
        
        memory_config = f'size={memory_str}'
        if hasattr(self, 'memory_model') and self.memory_model.get():
            memory_config += f',model={self.memory_model.get()}'
        cmd.extend(['-m', memory_config])
        
        # 主板型号配置（来自B站教程）
        machine_type = str(self.machine_type.get()).strip() if self.machine_type.get() else "pc"
        valid_machine_types = ['pc', 'q35', 'pc-q35-2.4', 'pc-q35-2.5', 'pc-q35-2.6', 'pc-q35-2.7', 'pc-q35-2.8', 'pc-q35-2.9', 'pc-q35-2.10', 'pc-q35-2.11', 'pc-q35-2.12', 'pc-q35-3.0', 'pc-q35-3.1', 'pc-q35-4.0', 'pc-q35-4.1', 'pc-q35-4.2', 'pc-q35-5.0', 'pc-q35-6.0', 'pc-q35-7.0']
        if machine_type not in valid_machine_types:
            machine_type = "pc"
            self.log("警告: 无效的主板类型，使用默认 pc")
        
        if hasattr(self, 'motherboard_model') and str(self.motherboard_model.get()).strip():
            motherboard_model = str(self.motherboard_model.get()).strip()
            # 验证主板型号只包含字母数字、连字符和下划线
            if re.match(r'^[\w\-]+$', motherboard_model):
                cmd.extend(['-machine', f'{machine_type},model={motherboard_model}'])
            else:
                cmd.extend(['-machine', machine_type])
                self.log("警告: 主板型号包含无效字符，已忽略")
        else:
            cmd.extend(['-machine', machine_type])
            
        # 显卡配置验证
        vga_type = str(self.vga_type.get()).strip() if self.vga_type.get() else "std"
        valid_vga_types = ['std', 'cirrus', 'vmware', 'qxl', 'virtio', 'none']
        if vga_type not in valid_vga_types:
            vga_type = "std"
            self.log("警告: 无效的显卡类型，使用默认 std")
        cmd.extend(['-vga', vga_type])
        
        # 加速模式验证
        accel = str(self.accel_type.get()).strip() if self.accel_type.get() else "none"
        valid_accels = ['none', 'tcg', 'kvm', 'whpx', 'hax', 'nvmm']
        if accel != 'none' and accel in valid_accels:
            cmd.extend(['-accel', accel])
        elif accel != 'none':
            self.log(f"警告: 无效的加速模式 {accel}，已忽略")
        
        # HPET配置
        if self.no_hpet.get():
            cmd.append('-no-hpet')
            
        # 杂项配置（来自B站教程）
        if hasattr(self, 'vmport') and self.vmport.get():
            cmd.append('-vmport')
            
        if hasattr(self, 'kernel_irqchip') and self.kernel_irqchip.get():
            cmd.append('-machine')  
            cmd[-1] += ',kernel_irqchip=on'
        
        if hasattr(self, 'dump_guest_core') and self.dump_guest_core.get():
            cmd.append('-d')  
            cmd[-1] += 'int,cpu_reset,guest_errors'
            
        if hasattr(self, 'mem_merge') and not self.mem_merge.get():
            cmd.append('-machine')
            cmd[-1] += ',mem-merge=off'
            
        if hasattr(self, 'hmat') and self.hmat.get():
            cmd.append('-machine')
            cmd[-1] += ',hmat=on'
            
        # 存储配置
        if self.disk_path.get() and str(self.disk_path.get()).strip():
            disk_path = str(self.disk_path.get()).strip()
            if os.path.exists(disk_path):
                # 使用选择的硬盘接口类型
                interface = self.disk_interface.get()
                if interface not in ['ide', 'sata', 'scsi', 'virtio', 'nvme']:
                    interface = 'ide'
                
                drive_config = f'file={disk_path},format=qcow2,if={interface}'
                
                # 添加硬盘型号（来自B站教程）
                if hasattr(self, 'disk_model') and str(self.disk_model.get()).strip():
                    drive_config += f',model={str(self.disk_model.get()).strip()}'
                
                cmd.extend(['-drive', drive_config])
            else:
                self.log(f"警告: 磁盘文件不存在: {disk_path}")
                messagebox.showwarning("警告", f"磁盘文件不存在: {disk_path}")
            
        if self.iso_path.get() and str(self.iso_path.get()).strip():
            iso_path = str(self.iso_path.get()).strip()
            if os.path.exists(iso_path):
                cmd.extend(['-cdrom', iso_path])
            else:
                self.log(f"警告: ISO文件不存在: {iso_path}")
                messagebox.showwarning("警告", f"ISO文件不存在: {iso_path}")
            
        if self.fda_path.get() and str(self.fda_path.get()).strip():
            fda_path = str(self.fda_path.get()).strip()
            if os.path.exists(fda_path):
                cmd.extend(['-fda', fda_path])
            else:
                self.log(f"警告: 软盘镜像文件不存在: {fda_path}")
                messagebox.showwarning("警告", f"软盘镜像文件不存在: {fda_path}")
        
        # BIOS文件配置
        if self.bios_path.get() and str(self.bios_path.get()).strip():
            bios_path = str(self.bios_path.get()).strip()
            if os.path.exists(bios_path):
                # 验证BIOS文件扩展名
                if bios_path.lower().endswith(('.fd', '.bin', '.rom')):
                    cmd.extend(['-bios', bios_path])
                    self.log(f"使用自定义BIOS文件: {bios_path}")
                else:
                    self.log(f"警告: BIOS文件扩展名无效，支持的格式: .fd, .bin, .rom")
                    messagebox.showwarning("警告", "BIOS文件格式无效，请使用.fd, .bin, 或.rom格式")
            else:
                self.log(f"警告: BIOS文件不存在: {bios_path}")
                messagebox.showwarning("警告", f"BIOS文件不存在: {bios_path}")
            
        # SMBIOS配置 - 安全处理特殊字符
        def escape_smbios_value(value):
            """转义SMBIOS值中的特殊字符"""
            if not value:
                return ""
            # 移除可能导致问题的字符，保留基本字符
            return re.sub(r'[^\w\s\-_\.@]', '', str(value).strip())
        
        if self.bios_vendor.get():
            cmd.extend(['-smbios', f'type=0,vendor={escape_smbios_value(self.bios_vendor.get())}'])
        if self.bios_version.get():
            cmd.extend(['-smbios', f'type=0,version={escape_smbios_value(self.bios_version.get())}'])
        if self.bios_release_date.get():
            cmd.extend(['-smbios', f'type=0,date={escape_smbios_value(self.bios_release_date.get())}'])
        if self.system_manufacturer.get():
            cmd.extend(['-smbios', f'type=1,manufacturer={escape_smbios_value(self.system_manufacturer.get())}'])
        if self.system_product_name.get():
            cmd.extend(['-smbios', f'type=1,product={escape_smbios_value(self.system_product_name.get())}'])
        if self.system_version.get():
            cmd.extend(['-smbios', f'type=1,version={escape_smbios_value(self.system_version.get())}'])
        if self.system_serial_number.get():
            cmd.extend(['-smbios', f'type=1,serial={escape_smbios_value(self.system_serial_number.get())}'])
        if self.system_uuid.get():
            # UUID格式验证
            try:
                uuid.UUID(self.system_uuid.get())
                cmd.extend(['-smbios', f'type=1,uuid={self.system_uuid.get()}'])
            except ValueError:
                self.log("警告: 无效的UUID格式，跳过UUID设置")
        if self.baseboard_manufacturer.get():
            cmd.extend(['-smbios', f'type=2,manufacturer={escape_smbios_value(self.baseboard_manufacturer.get())}'])
        if self.baseboard_product_name.get():
            cmd.extend(['-smbios', f'type=2,product={escape_smbios_value(self.baseboard_product_name.get())}'])
        if self.baseboard_serial_number.get():
            cmd.extend(['-smbios', f'type=2,serial={escape_smbios_value(self.baseboard_serial_number.get())}'])
        if self.chassis_manufacturer.get():
            cmd.extend(['-smbios', f'type=3,manufacturer={escape_smbios_value(self.chassis_manufacturer.get())}'])
        if self.chassis_type.get():
            cmd.extend(['-smbios', f'type=3,version={escape_smbios_value(self.chassis_type.get())}'])
            
        # 启动顺序验证
        boot_order = str(self.boot_order.get()).strip() if self.boot_order.get() else "cd"
        # 验证启动顺序只包含有效字符
        valid_boot_chars = {'a', 'b', 'c', 'd', 'n'}
        filtered_order = ''.join(c for c in boot_order.lower() if c in valid_boot_chars)
        if not filtered_order:
            filtered_order = "cd"
            self.log("警告: 无效的启动顺序，使用默认 cd")
        cmd.extend(['-boot', f'order={filtered_order}'])
            
        # 网络配置
        if self.network_model.get() and str(self.network_model.get()).strip():
            network_model = str(self.network_model.get()).strip()
            valid_models = ['e1000', 'e1000e', 'virtio-net-pci', 'rtl8139', 'vmxnet3', 'ne2k_pci']
            if network_model not in valid_models:
                network_model = 'e1000'
                self.log(f"警告: 无效的网络模型，使用默认 e1000")
            
            dns_server = str(self.dns_server.get()).strip() if self.dns_server.get() else "8.8.8.8"
            net_params = f'user,id=net0,dns={dns_server}'
            
            # 验证端口转发规则
            valid_port_forwards = []
            for rule in self.port_forwards:
                try:
                    host_str, guest_str = rule.split(':', 1)
                    host_port = int(host_str.strip())
                    guest_port = int(guest_str.strip())
                    
                    # 验证端口范围
                    if 1 <= host_port <= 65535 and 1 <= guest_port <= 65535:
                        # 警告特权端口
                        if host_port < 1024:
                            self.log(f"警告: 主机端口 {host_port} 是特权端口")
                        net_params += f',hostfwd=tcp::{host_port}-:{guest_port}'
                        valid_port_forwards.append(f"{host_port}:{guest_port}")
                    else:
                        self.log(f"警告: 无效端口范围: {rule}")
                except ValueError:
                    self.log(f"警告: 端口转发格式错误: {rule}")
            
            cmd.extend(['-netdev', net_params])
            cmd.extend(['-device', f'{network_model},netdev=net0'])
            
            if self.mac_address.get() and str(self.mac_address.get()).strip():
                mac = str(self.mac_address.get()).strip()
                # MAC地址格式验证
                if re.match(r'^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', mac):
                    cmd[-1] += f',mac={mac}'
                else:
                    self.log(f"警告: 无效的MAC地址格式: {mac}")
                    # 生成随机MAC地址
                    random_mac = f"52:54:00:{random.randint(0, 255):02x}:{random.randint(0, 255):02x}:{random.randint(0, 255):02x}"
                    cmd[-1] += f',mac={random_mac}'
                    self.log(f"使用随机MAC地址: {random_mac}")
                
        # USB配置
        if self.enable_usb.get():
            cmd.extend(['-usb', '-device', 'usb-tablet'])
            
            # 添加额外的USB设备（如果配置）
            if hasattr(self, 'usb_devices') and self.usb_devices:
                for usb_device in self.usb_devices:
                    if usb_device.get('enabled', False) and usb_device.get('device'):
                        device = str(usb_device['device']).strip()
                        if device.startswith('usb-') or device in ['usb-tablet', 'usb-mouse', 'usb-kbd', 'usb-storage']:
                            cmd.extend(['-device', device])
            
        # 共享文件夹配置
        if self.enable_shared_folder.get():
            shared_path = str(self.shared_folder_path.get()).strip() if self.shared_folder_path.get() else ""
            shared_tag = str(self.shared_folder_tag.get()).strip() if self.shared_folder_tag.get() else "hostshare"
            
            if shared_path and os.path.exists(shared_path) and os.path.isdir(shared_path):
                # 验证路径安全性
                try:
                    # 确保路径是绝对路径且没有特殊字符
                    abs_path = os.path.abspath(shared_path)
                    # 转义路径中的特殊字符
                    safe_path = abs_path.replace('\\', '/')
                    safe_tag = re.sub(r'[^\w\-_]', '', shared_tag)[:32]  # 限制标签长度
                    
                    cmd.extend(['-virtfs', f'local,path={safe_path},mount_tag={safe_tag},security_model=passthrough,id=fs0'])
                    self.log(f"已启用共享文件夹: {safe_path} (标签: {safe_tag})")
                except Exception as e:
                    self.log(f"共享文件夹配置错误: {str(e)}")
                    messagebox.showerror("错误", f"共享文件夹配置错误: {str(e)}")
            else:
                if shared_path:
                    self.log(f"共享文件夹路径不存在或不是目录: {shared_path}")
                    messagebox.showwarning("警告", f"共享文件夹路径不存在或不是目录: {shared_path}")
                
        # 快照配置
        if self.enable_snapshot.get():
            cmd.extend(['-snapshot'])
            self.log(tr('snapshot_mode'))
            
        # 额外参数
        if self.extra_params.get() and self.extra_params.get().strip():
            # 分割参数并处理引号
            import shlex
            try:
                extra_args = shlex.split(self.extra_params.get().strip())
                cmd.extend(extra_args)
            except Exception as e:
                self.log(f"警告: 额外参数格式错误，将忽略: {str(e)}")
            
        # 记录命令
        full_cmd = ' '.join(cmd)
        self.log("=" * 60)
        self.log(tr('vm_starting'))
        self.log(tr('vm_name') + f": {self.current_vm['name']}")
        self.log(f"完整命令: {full_cmd}")
        
        # 启动线程
        thread = threading.Thread(target=self.run_qemu, args=(cmd,))
        thread.daemon = True
        thread.start()
        self.running_thread = thread
        
        # 更新设置中的最后使用的虚拟机
        self.settings['last_vm'] = self.current_vm['file']
        save_settings(self.settings)
        
    def stop_vm(self):
        """停止当前运行的虚拟机"""
        if hasattr(self, 'qemu_process') and self.qemu_process and self.qemu_process.poll() is None:
            try:
                self.qemu_process.terminate()
                self.qemu_process.wait(timeout=5)
                self.log("虚拟机已正常停止")
                self.status_bar.config(text=tr('vm_stopped'))
            except subprocess.TimeoutExpired:
                self.qemu_process.kill()
                self.qemu_process.wait()
                self.log("虚拟机已被强制终止")
                self.status_bar.config(text=tr('vm_stopped'))
            except Exception as e:
                self.log(f"停止虚拟机时出错: {str(e)}")
            finally:
                self.qemu_process = None
                if hasattr(self, 'running_thread'):
                    self.running_thread = None
    
    def run_qemu(self, cmd):
        """运行QEMU进程"""
        try:
            self.status_bar.config(text=tr('vm_starting'))
            self.log(tr('vm_starting'))
            
            # 确保之前的进程已停止
            self.stop_vm()
            
            # 修复UnicodeDecodeError
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                bufsize=1,
                universal_newlines=False
            )
            
            self.qemu_process = process
            self.log(f"虚拟机进程已启动，PID: {process.pid}")
            self.status_bar.config(text=tr('vm_running'))
            
            # 实时输出日志（修复解码问题）
            def log_output(stream, prefix):
                decoder = io.TextIOWrapper(stream, encoding='utf-8', errors='ignore')
                while True:
                    line = decoder.readline()
                    if not line:
                        break
                    self.log(f"{prefix}: {line.strip()}")
            
            stdout_thread = threading.Thread(target=log_output, args=(process.stdout, "输出"))
            stderr_thread = threading.Thread(target=log_output, args=(process.stderr, "错误"))
            
            stdout_thread.daemon = True
            stderr_thread.daemon = True
            
            stdout_thread.start()
            stderr_thread.start()
            
            # 等待进程结束
            process.wait()
            
            if process.poll() is not None:
                self.status_bar.config(text=tr('vm_stopped'))
                self.log(tr('vm_stopped'))
                self.qemu_process = None
                
        except Exception as e:
            self.status_bar.config(text=tr('vm_failed'))
            self.log(tr('vm_failed') + f": {str(e)}")
            messagebox.showerror(tr('vm_failed'), str(e))
            self.qemu_process = None

    # ==================== 新增工具方法 ====================
    
    def backup_configs(self):
        """备份所有配置"""
        try:
            # 选择保存位置
            filename = filedialog.asksaveasfilename(
                defaultextension=".zip",
                filetypes=[("ZIP 文件", "*.zip")]
            )
            if not filename:
                return
            
            # 创建ZIP文件
            with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
                # 备份虚拟机配置
                for file in VM_CONFIG_DIR.glob('*.json'):
                    zipf.write(file, arcname=file.name)
                
                # 备份设置文件
                if SETTINGS_FILE.exists():
                    zipf.write(SETTINGS_FILE, arcname=SETTINGS_FILE.name)
            
            self.log(tr('backup_success', filename))
            messagebox.showinfo(tr('backup_success', filename), tr('backup_success', filename))
        except Exception as e:
            messagebox.showerror("备份失败", f"备份配置时出错: {str(e)}")
            self.log(f"备份配置失败: {str(e)}")
    
    def restore_configs(self):
        """恢复虚拟机配置"""
        try:
            filename = filedialog.askopenfilename(
                filetypes=[("ZIP 文件", "*.zip")]
            )
            if not filename:
                return
            
            # 解压ZIP文件
            with zipfile.ZipFile(filename, 'r') as zipf:
                # 恢复虚拟机配置
                for name in zipf.namelist():
                    if name.endswith('.json'):
                        # 只恢复虚拟机配置，不覆盖设置
                        if name != SETTINGS_FILE.name:
                            data = zipf.read(name)
                            (VM_CONFIG_DIR / name).write_bytes(data)
            
            self.log(tr('restore_success'))
            messagebox.showinfo(tr('restore_success'), tr('restore_success'))
            # 重新加载虚拟机列表
            self.load_vm_list()
        except Exception as e:
            messagebox.showerror("恢复失败", f"恢复配置时出错: {str(e)}")
            self.log(f"恢复配置失败: {str(e)}")
    
    def reset_qemu_path(self):
        """重置QEMU路径为自动检测值"""
        path = find_qemu_executable()
        if path:
            self.qemu_path.set(path)
            self.log(tr('qemu_detected', path))
            # 更新加速选项
            self.accel_options = detect_accel_options(path)
            self.cpu_features = detect_cpu_features(path)
            self.update_accel_options()
            messagebox.showinfo(tr('qemu_detected', path), tr('qemu_detected', path))
        else:
            messagebox.showerror(tr('qemu_not_found'), tr('qemu_not_found'))
    
    def check_updates(self):
        """检查更新"""
        # 这里只是一个示例，实际应该从网络获取更新信息
        messagebox.showinfo("检查更新", "当前已是最新版本: VMboxy-PC Beta")
        self.log("已检查更新")
    
    def clear_cache(self):
        """清除缓存（日志）"""
        try:
            # 删除日志目录下的所有文件
            for file in LOG_DIR.glob('*'):
                if file.is_file():
                    file.unlink()
            self.log(tr('clear_cache_success'))
            messagebox.showinfo(tr('clear_cache_success'), tr('clear_cache_success'))
        except Exception as e:
            messagebox.showerror("清除缓存失败", f"清除缓存时出错: {str(e)}")
            self.log(f"清除缓存失败: {str(e)}")

# ==================== 主程序入口 ====================

def main():
    """主程序入口"""
    try:
        app = VMBoxyGUI()
        app.mainloop()
    except Exception as e:
        logger.error(f"程序异常: {e}")
        messagebox.showerror("程序错误", str(e))

if __name__ == "__main__":
    main()